与えられたサンプルデータ:
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
使用したことに注意してください。DBサーバーがこれらを最適化するのははるかに簡単であり、のsで発生する可能性のある紛らわしい問題を回避します。NOT EXISTS
OUTER JOIN
NULL
NOT IN
私は当初、定式化を支持しましたOUTER JOIN
が、少なくとも9.1では、テストデータを使用してNOT EXISTS
フォームが同じ計画に最適化されます。
NOT IN
あなたの場合のように、シリーズが大きい場合、両方とも以下の定式化よりも優れたパフォーマンスを発揮します。NOT IN
以前は、テスト対象のすべてのタプルに対してリストの線形検索を実行するようにPgに要求していましたIN
が、クエリプランを調べると、Pgは今すぐハッシュするのに十分賢い可能性があります。(クエリプランナーによってにNOT EXISTS
変換されます)そしてより良く機能します。JOIN
JOIN
このNOT IN
定式化は、NULLが存在する場合は混乱を招き、commandid
非効率になる可能性があります。
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バウンドで実行されました。