5

次の表を想像してください。

テーブルボックスを作成します( id int, name text, ...);

テーブルの作成

テーブルは次のようになります。

ボックス:
ID | 名前
1 | オレンジのみ
2 | オレンジのみ2
3 | オレンジバナナ
4 | その他

物事の受信箱:
ID | box_id | もの
1 | 1 | オレンジ
2 | 1 | オレンジ
3 | 2 | オレンジ
4 | 3 | オレンジ
5 | 3 | バナナ
6 | 4 | オレンジ
7 | 4 | りんご
8 | 4 | バナナ

オレンジが少なくとも 1 つ含まれ、オレンジ以外が何も含まれていないボックスを選択するにはどうすればよいですか?

数十万個の箱があり、おそらく百万個のものが箱に入っていると仮定すると、これはどのようにスケーリングしますか?

結果セットをスクリプトで後処理するのではなく、可能であれば、これをすべて SQL に保持したいと思います。

私はpostgresとmysqlの両方を使用しているため、mysqlがサブクエリを最適化しないことを考えると、サブクエリはおそらく悪いです(とにかくバージョン6より前)。

4

2 に答える 2

6
SELECT b.*
FROM boxes b JOIN thingsinboxes t ON (b.id = t.box_id)
GROUP BY b.id
HAVING COUNT(DISTINCT t.thing) = 1 AND SUM(t.thing = 'orange') > 0;

GROUPBYを使用しない別のソリューションは次のとおりです。

SELECT DISTINCT b.*
FROM boxes b
  JOIN thingsinboxes t1 
    ON (b.id = t1.box_id AND t1.thing = 'orange')
  LEFT OUTER JOIN thingsinboxes t2 
    ON (b.id = t2.box_id AND t2.thing != 'orange')
WHERE t2.box_id IS NULL;

いつものように、クエリのスケーラビリティまたはパフォーマンスについて結論を出す前に、現実的なデータセットでそれを試し、パフォーマンスを測定する必要があります。

于 2009-01-26T22:19:54.660 に答える
2

thingBill Karwin のクエリは問題ないと思いますが、オレンジが含まれるボックスの割合が比較的少ない場合は、フィールドのインデックスを使用して処理を高速化できるはずです。

SELECT b.*
FROM boxes b JOIN thingsinboxes t1 ON (b.id = t1.box_id)
WHERE t1.thing = 'orange'
AND NOT EXISTS (
    SELECT 1
    FROM thingsinboxes t2
    WHERE t2.box_id = b.id
    AND t2.thing <> 'orange'
)
GROUP BY t1.box_id

サブクエリはWHERE NOT EXISTSオレンジ色ごとに 1 回だけ実行されるため、オレンジ色が多くない場合はそれほど高価ではありません。

于 2009-01-26T22:45:05.560 に答える