これが私のデータの簡略化されたバージョンです:
products:
+----+-----------+
| id | name |
+----+-----------+
| 1 | Product X |
| 2 | Product Y |
| 3 | Product Z |
+----+-----------+
categories:
+----+---------------+
| id | name |
+----+---------------+
| 1 | Hotel |
| 2 | Accommodation |
+----+---------------+
category_product
+----+------------+-------------+
| id | product_id | category_id |
+----+------------+-------------+
| 1 | 1 | 1 |
| 2 | 1 | 2 |
| 3 | 2 | 1 |
| 4 | 3 | 2 |
+----+------------+-------------+
「ホテル」と「宿泊施設」の両方のproducts
カテゴリ (例: 製品 X) のみを取得する効率的なクエリを作成するにはどうすればよいですか?
私は最初に参加アプローチを試みました
SELECT *
FROM products p
JOIN category_product cp
ON p.id = cp.product_id
WHERE cp.category_id = 1 OR cp.category_id = 2
^両方を含むようにクエリを制限しないため、これは機能しません。
機能するサブクエリを使用するアプローチを見つけました...しかし、パフォーマンス上の理由からサブクエリに対して警告されました:
SELECT *
FROM products p
WHERE
(
SELECT id
FROM category_product
WHERE product_id = p.id
AND category_id = 1
)
AND
(
SELECT id
FROM category_product
WHERE product_id = p.id
AND category_id = 2
)
より良い解決策はありますか (または代替案はありますか)? カテゴリを製品の追加の列に非正規化することを検討しましたが、理想的にはそれを避けたいと思います. 魔法の弾丸の解決を願って!
アップデート
回答で提供されている(優れた)ソリューションのいくつかを実行しました:私のデータは235 000のcategory_product行と58 000の製品であり、明らかにベンチマークは常に環境やインデックスなどに依存しています.
「関係分割」 @podiluska
2 categories: 2826 rows ~ 20ms
5 categories: 46 rows ~ 25-30 ms
8 categories: 1 rows ~ 25-30 ms
「存在する場所」@Tim Schmelter
2 categories: 2826 rows ~ 5-7ms
5 categories: 46 rows ~ 30 ms
8 categories: 1 rows ~ 300 ms
より多くのカテゴリが投入されると、結果が発散し始めることがわかります。一貫した結果が得られるため、「関係分割」の使用を検討しますが、実装により、「存在する場所」も確認する可能性があります (長い形式のhttp ://pastebin.com/6NRX0QbJ )