与えられたサンプルデータ:
create table results ( commandid integer primary key);
insert into results (commandid) select * from generate_series(1,1000);
delete from results where random() < 0.20;
これは機能します:
SELECT s.i AS missing_cmd
FROM generate_series(0,1000) s(i)
WHERE NOT EXISTS (SELECT 1 FROM results WHERE commandid = s.i);
この代替定式化も同様です:
SELECT s.i AS missing_cmd
FROM generate_series(0,1000) s(i)
LEFT OUTER JOIN results ON (results.commandid = s.i)
WHERE results.commandid IS NULL;
上記の両方とも、私のテストでは同じクエリプランになるようですが、EXPLAIN ANALYZE
を使用してデータベース上のデータと比較する必要があります。 どちらが最適かを確認します。
説明
NOT IN
の代わりに注意してください NOT EXISTS
を使用しました 1つの定式化でサブクエリを使用し、通常のOUTER JOIN
他で。 DBサーバーがこれらを最適化するのははるかに簡単であり、NULL
で発生する可能性のある紛らわしい問題を回避します。 s in NOT IN
。
私は当初、OUTER JOIN
を好みました 公式化されていますが、少なくとも9.1では、私のテストデータではNOT EXISTS
フォームは同じ計画に最適化されます。
どちらもNOT IN
よりもパフォーマンスが優れています あなたの場合のように、シリーズが大きい場合の以下の定式化。 NOT IN
IN
の線形検索を実行するようにPgに要求するために使用されます テストされているすべてのタプルのリストですが、クエリプランを調べると、Pgは今すぐハッシュするのに十分賢い可能性があることがわかります。 NOT EXISTS
(JOIN
に変換されます クエリプランナーによる)およびJOIN
うまく機能します。
NOT IN
NULL commandid
が存在する場合、定式化はどちらも混乱を招きます sおよび非効率的である可能性があります:
SELECT s.i AS missing_cmd
FROM generate_series(0,1000) s(i)
WHERE s.i NOT IN (SELECT commandid FROM results);
だから私はそれを避けたいと思います。 1,000,000行で、他の2つは1.2秒で完了し、NOT IN
退屈してキャンセルするまで、定式化はCPUバウンドで実行されました。