Tulis ulang kueri untuk menggunakan WHERE
bukannya HAVING
. Karena WHERE
diterapkan ketika MySQL melakukan pencarian pada baris dan dapat menggunakan index. HAVING
diterapkan setelah baris dipilih untuk memfilter hasil yang sudah dipilih. HAVING
secara desain tidak dapat menggunakan indeks.
Anda dapat melakukannya, misalnya dengan cara ini:
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
Perbarui
Kami menggabungkan setiap tabel dua kali.
Pertama untuk memeriksa apakah tabel tersebut berisi beberapa nilai (kondisi dari FIND_IN_SET
).
Gabungan kedua akan menghasilkan data untuk GROUP_CONCAT
untuk memilih semua nilai produk dari tabel.
Perbarui 2
Seperti komentar @Matt Raines, jika kita tidak perlu mencantumkan nilai produk dengan GROUP_CONCAT
, kueri menjadi lebih sederhana:
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
Ini akan memilih semua produk dengan tiga atribut yang difilter.