2012-06-22 45 views
5

Tengo 3 tablas: productos, categorías y pro_cat_link. Un producto puede vincularse a una o más categorías a través de la tabla pro_cat_link.Consulta SQL para encontrar productos que coincidan con un conjunto de categorías

Mi consulta debe responder al siguiente problema: encuentre todos los productos que coincidan con un conjunto de categorías. Ej .: encuentre todos los productos que sean "amarillos Y frutales Y dulces".

Al investigar este problema en tanto que pude encontrar sólo la solución de lo que estoy usando actualmente: Complicated SQL Query--finding items matching multiple different foreign keys

En mi caso, mi consulta es la siguiente:

SELECT products.id, COUNT(DISTINCT categories.id) as countCat 
FROM products 
INNER JOIN pro_cat_link ON (pro_cat_link.product_id = products.id) 
WHERE pro_cat_link.category_id IN (3,6,8,10) 
GROUP BY product.id 
ORDER BY product.date DESC 
HAVING countCat = 4 

En otras palabras, seleccione todos los productos que coincidan con uno de los identificadores de categoría (3,6,8,10) y conserve solo aquellos que tienen exactamente 4 categorías coincidentes.

Esto funciona bien, pero estoy teniendo problemas de rendimiento ya que el COUNT(), GROUP BY, ORDER BY hace que la indexación sea muy limitada. ¿Alguien puede pensar en una mejor manera de resolver ese problema?

+0

Supongo que simplemente hacer una unión para cada categoría lleva demasiado tiempo? – Jodaka

+0

@Jodaka Sí. Los chicos de administración requieren que un usuario pueda elegir tantas categorías como quiera;) – Tchoupi

Respuesta

2

Puede eliminar los problemas de rendimiento de agrupar y contar si almacenó esa información en alguna parte. Puede agregar una columna a los productos llamados total_categories que le indicarán en cuántas categorías participa el producto. Entonces, simplemente podría decir where total_categories = 4. Esto puede ser más difícil de mantener si los productos a menudo cambian sus categorías porque debe actualizar constantemente este campo correctamente, y luego debe decidir si desea hacer eso en el código de la aplicación o en un desencadenante o en un procedimiento almacenado. ...

Normalmente no creo que sea una buena idea almacenar dichos metadatos directamente en una tabla, pero si el rendimiento es realmente tan malo, podría valer la pena considerarlo.

+0

+1 Deshacerse del 'GROUP BY' es definitivamente el camino a seguir. Lo probaré. – Tchoupi

1

Si no tiene demasiadas categorías, en lugar de hacer un seguimiento del recuento de columnas, puede tener una cadena de bits que represente las categorías en que se encuentra (es decir, un 1 en la posición i significa que el producto está en la categoría i , y 0 significa que no está en la categoría). Luego, cuando busca un grupo de categorías, genera una cadena de bits para esa búsqueda y AND todas las cadenas de categoría con esta cadena. Los que están en la categoría correcta producirán la cadena de búsqueda como respuesta.

Por ejemplo, supongamos que tiene diez categorías. Item1 está en las categorías 1, 3, 5, 6, 8, 10, por lo que su cadena de categoría es 1010110101. Item2 está en las categorías 1, 2, 4, 6, 8, 10, por lo que su cadena de categoría es 1010101011. Al buscar 3, 6, 8 y 10, generaría la cadena s = 1010100100. Item1 & s = 1010100100 = s. Item2 & s = 1010100000 <> s.

Además, no tiene que almacenarlo como una cadena, solo podría almacenarlo como la base real de 10 equivalentes. Entonces Item1, Item2 ys son 693, 683 y 676 respectivamente. 693 & 676 = 676, pero 683 & 676 = 672. Luego, si está agregando un producto a la categoría i, simplemente actualice su número de categoría por 2^(i - 1), y si lo está eliminando de la categoría i, solo resta 2^(i - 1).

Por supuesto, si tiene más categorías que bits en una int de MySQL, esto no funcionará en absoluto. Además, como FrustratedWithFormsDes señala en su respuesta, esto invoca todos los problemas de actualización tanto de pro_cat_link como de esta tabla (por supuesto, dependiendo de para qué pro_cat_link se use, esto podría eliminarlo por completo). Además, si una categoría cambia los números, debe actualizar todo.

+0

+1 para una idea interesante! – FrustratedWithFormsDesigner

Cuestiones relacionadas