给定样本数据:
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
了子查询,而在另一个公式中使用了普通查询OUTER JOIN
。数据库服务器更容易优化这些,并且避免了NULL
s in可能出现的令人困惑的问题NOT IN
。
我最初喜欢这个OUTER JOIN
公式,但至少在 9.1 中,我的测试数据NOT EXISTS
表格优化到了相同的计划。
NOT IN
当系列很大时,两者都会比下面的公式表现更好,就像你的情况一样。NOT IN
过去需要 PgIN
对每个被测试的元组进行列表的线性搜索,但对查询计划的检查表明 Pg 可能足够聪明,现在可以散列它。(由查询计划器NOT EXISTS
转换为 a )并且工作得更好。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 行,另外两个在 1.2 秒内完成,NOT IN
公式运行 CPU 密集型,直到我感到无聊并取消它。