2010-09-04 17 views
6

Justo después de algunas opiniones sobre la mejor manera de lograr los siguientes resultados:MySQL - cómo optimizar la consulta a contar los votos

me gustaría guardar en mis productos de base de datos MySQL, que puede ser votada por los usuarios (cada voto vale +1). También quiero poder ver cuántas veces en total un usuario ha votado.

A mi modo sencillo, la siguiente estructura de la tabla sería ideal:

table: product   table: user   table: user_product_vote  
+----+-------------+ +----+-------------+ +----+------------+---------+ 
| id | product | | id | username | | id | product_id | user_id | 
+----+-------------+ +----+-------------+ +----+------------+---------+ 
| 1 | bananas  | | 1 | matthew  | | 1 | 1   | 2  | 
| 2 | apples  | | 2 | mark  | | 2 | 2   | 2  | 
| .. | ..   | | .. | ..   | | .. | ..   | ..  | 

De esta manera me puede hacer un conteo de la mesa user_product_vote para cada producto o usuario.

Por ejemplo, cuando quiero mirar hacia arriba plátanos y el número de votos a mostrar en una página web que pude realizar la siguiente consulta:

SELECT p.product AS product, COUNT(v.id) as votes 
FROM product p 
LEFT JOIN user_product_vote v ON p.id = v.product_id 
WHERE p.id =1 

Si mi sitio se convirtió en un enorme éxito (todos podemos sueño) y tenía miles de usuarios votando sobre miles de productos, me temo que realizar tal COUNT con cada vista de página sería altamente ineficiente en términos de recursos del servidor.

Un enfoque más simple sería tener una columna de 'votos' en la tabla de productos que se incrementa cada vez que se agrega un voto.

table: product    
+----+-------------+-------+ 
| id | product | votes | 
+----+-------------+-------+ 
| 1 | bananas  | 2  | 
| 2 | apples  | 5  | 
| .. | ..   | .. | 

Si bien esto es más respetuosa de los recursos - que se pierdan datos (por ejemplo, ya no puedo evitar que una persona pueda votar dos veces ya que no hay ningún registro de su actividad votación.).

Mis preguntas son:
i) ¿Estoy demasiado preocupado por los recursos del servidor y debería seguir con la opción de tres tablas? (es decir, necesito tener más fe en la capacidad de la base de datos para manejar consultas grandes)
ii) es su forma más eficiente de lograr el resultado sin perder información

+1

otro problema que tiene es probablemente nunca ha tenido un sitio web que recibe tráfico masivo, por lo que no está seguro de las capacidades de php/mysql, le aseguro que mysql puede manejar miles de consultas por segundo con caída de rendimiento a mucho – RobertPitt

Respuesta

6

Nunca se preocupe demasiado por los recursos; cuando comienza a construir una aplicación, siempre debe tener en cuenta los recursos, espacio, velocidad, etc. Si el tráfico de su sitio creció drásticamente y nunca construyó para los recursos, comienza a recibir en problemas

En cuanto al sistema de votación, personalmente me gustaría mantener los votos de esta manera:

table: product   table: user    table: user_product_vote  
+----+-------------+ +----+-------------+ +----+------------+---------+ 
| id | product | | id | username | | id | product_id | user_id | 
+----+-------------+ +----+-------------+ +----+------------+---------+ 
| 1 | bananas  | | 1 | matthew  | | 1 | 1   | 2  | 
| 2 | apples  | | 2 | mark  | | 2 | 2   | 2  | 
| .. | ..   | | .. | ..   | | .. | ..   | ..  | 

Razones:

En primer lugar user_product_vote no contiene texto, manchas, etc., es puramente número entero por lo que ocupa menos recursos de todos modos.

En segundo lugar, usted tiene más de una puerta a nuevas entidades dentro de su aplicación, tales como votos totales pasado 24 horas, el producto Mayor puntuación en los últimos 24 horas, etc.

tomar este ejemplo por ejemplo:

table: user_product_vote  
+----+------------+---------+-----------+------+ 
| id | product_id | user_id | vote_type | time | 
+----+------------+---------+-----------+------+ 
| 1 | 1   | 2  | product |224.. | 
| 2 | 2   | 2  | page  |218.. | 
| .. | ..   | ..  | ..  | .. | 

y una consulta sencilla:

SELECT COUNT(id) as total FROM user_product_vote WHERE vote_type = 'product' AND time BETWEEN(....) ORDER BY time DESC LIMIT 20 

Otra cosa es si un usuario ha votado en 1AM y luego trató de votar de nuevo en 2PM, puede verificar fácilmente cuándo fue la última vez que votaron y si se les debería permitir votar de nuevo.

Hay tantas oportunidades que se perderá si se atiene a su ejemplo incremental.


En lo que respecta a su count(), no importa cuánto a optimizar sus consultas en realidad no lo haría una diferencia a gran escala.

Con una base de usuarios extremadamente grande, su uso de recursos se analizará desde una perspectiva diferente, como equilibradores de carga, principalmente configuraciones de servidor, Apache, captura, etc., hay mucho que puede hacer con sus consultas.

0

Tiene que equilibrar el deseo de su sitio para realizar rápidamente (en el que el segundo esquema sería mejor) y la capacidad de contar votos para usuarios específicos y evitar el voto doble (para lo cual elegiría el primer esquema). Como solo está utilizando columnas de enteros para la tabla user_product_vote, no veo cómo el rendimiento podría sufrir demasiado. Las relaciones de muchos a muchos son comunes, como ha implementado con user_product_vote. Si desea contar los votos para usuarios específicos y evitar el voto doble, un user_product_vote es la única forma en que puedo pensar en implementarlo, ya que cualquier otro podría dar como resultado registros escasos, registros duplicados y todo tipo de cosas malas.

1

¿Por qué no mezclar y combinar ambos? Simplemente tenga los recuentos finales en las tablas de productos y usuarios, para que no tenga que contar cada vez y tener la tabla de votos, para que no haya publicaciones dobles.

Editar: Para explicarlo un poco más, la tabla de productos y usuarios tendrá una columna llamada "votos". Cada vez que la inserción sea exitosa en user_product_vote, incremente los registros de usuarios y productos relevantes. Esto evitaría los votos dupe y no tendrá que ejecutar la consulta de conteo complejo cada vez también.

Edit: También asumo que ha creado un índice único en product_id y user_id, en este caso cualquier intento de duplicación fallará automáticamente y no tendrá que verificar en la tabla antes de insertar. Solo para asegurarse de que la consulta de inserción se ejecutó y obtuvo un valor válido para el "id" en el formulario insert_id

0

No desea actualizar la tabla del producto directamente con un agregado cada vez que alguien vota - esto bloqueará filas de productos que luego afectarán otras consultas que están utilizando productos.

Suponiendo que no todas las consultas sobre productos deban incluir la columna de votos, puede mantener una tabla de votos del producto que retenga los totales acumulados y mantenga su tabla de producto de usuario como medio para hacer cumplir su voto del usuario según las reglas del negocio del producto/y revisión de cuentas.

2

Si mi sitio se convirtió en un gran éxito (todos podemos soñar) y tenía miles de usuarios votando sobre miles de productos, me temo que la realización de semejante COUNT con cada página sería muy ineficiente en términos de recursos de servidor .

No pierdas el tiempo resolviendo problemas imaginarios. mysql es perfectamente capaz de procesar miles de registros en fracciones de segundo; para eso están las bases de datos. Una base de datos y una estructura de código simples y limpios son mucho más importantes que la mítica "optimización" que nadie necesita.

Cuestiones relacionadas