Przepisz zapytanie, aby użyć WHERE
zamiast HAVING
. Ponieważ WHERE
jest stosowany, gdy MySQL wykonuje wyszukiwanie w wierszach i może używać indeksu. HAVING
jest stosowany po zaznaczeniu wierszy w celu filtrowania już wybranych wyników. HAVING
z założenia nie może używać indeksów.
Możesz to zrobić na przykład w ten sposób:
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
Aktualizacja
Dołączamy do każdej tabeli dwa razy.
Najpierw sprawdzamy, czy zawiera jakąś wartość (warunek z FIND_IN_SET
).
Drugie sprzężenie wygeneruje dane dla GROUP_CONCAT
aby wybrać wszystkie wartości produktów z tabeli.
Aktualizacja 2
Jak skomentował @Matt Raines, jeśli nie potrzebujemy listy wartości produktów z GROUP_CONCAT
zapytanie staje się jeszcze prostsze:
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
Spowoduje to wybranie wszystkich produktów z trzema filtrowanymi atrybutami.