Reescreva a consulta para usar
WHERE
em vez de HAVING
. Porque WHERE
é aplicado quando o MySQL realiza pesquisa em linhas e pode usar index. HAVING
é aplicado depois que as linhas são selecionadas para filtrar o resultado já selecionado. HAVING
por design não pode usar índices.Você pode fazer isso, por exemplo, desta forma:
SELECT p.id, p.name, p.default_image_id,
GROUP_CONCAT( DISTINCT pc.colour_id ) AS product_colours,
GROUP_CONCAT( DISTINCT pt.tag_id ) AS product_tags,
GROUP_CONCAT( DISTINCT ps.tag_id ) AS product_sizes
FROM shop_products p
JOIN shop_product_to_colours pc_test ON p.id = pc_test.product_id AND pc_test.colour_id = 18
JOIN shop_products_to_tag pt_test ON p.id = pt_test.product_id AND pt_test.tag_id = 1
JOIN shop_product_colour_to_sizes ps_test ON p.id = ps_test.product_id AND ps_test.tag_id = 17
JOIN shop_product_to_colours pc ON p.id = pc.product_id
JOIN shop_products_to_tag pt ON p.id = pt.product_id
JOIN shop_product_colour_to_sizes ps ON p.id = ps.product_id
WHERE p.category_id = '50'
GROUP BY p.id
ORDER BY p.name ASC
Atualizar
Estamos juntando cada tabela duas vezes.
Primeiro para verificar se ela contém algum valor (condição de
FIND_IN_SET
).A segunda junção produzirá dados para
GROUP_CONCAT
para selecionar todos os valores do produto da tabela. Atualização 2
Como @Matt Raines comentou, se não precisarmos listar valores de produtos com
GROUP_CONCAT
, a consulta fica ainda mais simples:SELECT p.id, p.name, p.default_image_id
FROM shop_products p
JOIN shop_product_to_colours pc ON p.id = pc.product_id
JOIN shop_products_to_tag pt ON p.id = pt.product_id
JOIN shop_product_colour_to_sizes ps ON p.id = ps.product_id
WHERE p.category_id = '50'
AND (pc.colour_id = 18 AND pt.tag_id = 1 AND ps.tag_id = 17)
GROUP BY p.id
ORDER BY p.name ASC
Isso selecionará todos os produtos com três atributos filtrados.