PostgreSQL:NOT IN与EXCEPT性能差异(编辑#2)

Dan*_*ons 25 sql postgresql

我有两个功能相同的查询.其中一个表现很好,另一个表现很差.我没有看到性能差异出现在哪里.

查询#1:

SELECT id 
FROM subsource_position
WHERE
  id NOT IN (SELECT position_id FROM subsource)
Run Code Online (Sandbox Code Playgroud)

这回来了以下计划:

                                  QUERY PLAN                                   
-------------------------------------------------------------------------------
 Seq Scan on subsource_position  (cost=0.00..362486535.10 rows=128524 width=4)
   Filter: (NOT (SubPlan 1))
   SubPlan 1
     ->  Materialize  (cost=0.00..2566.50 rows=101500 width=4)
           ->  Seq Scan on subsource  (cost=0.00..1662.00 rows=101500 width=4)
Run Code Online (Sandbox Code Playgroud)

查询#2:

SELECT id FROM subsource_position
EXCEPT
SELECT position_id FROM subsource;
Run Code Online (Sandbox Code Playgroud)

计划:

                                           QUERY PLAN                                            
-------------------------------------------------------------------------------------------------
 SetOp Except  (cost=24760.35..25668.66 rows=95997 width=4)
   ->  Sort  (cost=24760.35..25214.50 rows=181663 width=4)
         Sort Key: "*SELECT* 1".id
         ->  Append  (cost=0.00..6406.26 rows=181663 width=4)
               ->  Subquery Scan on "*SELECT* 1"  (cost=0.00..4146.94 rows=95997 width=4)
                     ->  Seq Scan on subsource_position  (cost=0.00..3186.97 rows=95997 width=4)
               ->  Subquery Scan on "*SELECT* 2"  (cost=0.00..2259.32 rows=85666 width=4)
                     ->  Seq Scan on subsource  (cost=0.00..1402.66 rows=85666 width=4)
(8 rows)
Run Code Online (Sandbox Code Playgroud)

我有一种感觉,我错过了一个关于我的一个查询的明显不好的事情,或者我错误配置了PostgreSQL服务器.我原本预计这NOT IN会很好地优化; 是NOT IN始终存在性能问题,还是有它在这里不优化的理由?

其他数据:

=> select count(*) from subsource;
 count 
-------
 85158
(1 row)

=> select count(*) from subsource_position;
 count 
-------
 93261
(1 row)
Run Code Online (Sandbox Code Playgroud)

编辑:我现在修复了下面提到的AB!= BA问题.但我所陈述的问题仍然存在:查询#1仍然比查询#2差很多.我相信这是因为两个表都有相似的行数.

编辑2:我正在使用PostgresQL 9.0.4.我不能使用EXPLAIN ANALYZE,因为查询#1需要太长时间.所有这些列都不是NULL,因此应该没有区别.

编辑3:我在这两列上都有一个索引.我还没有完成查询#1(约10分钟后放弃).查询#2立即返回.

Ant*_*bbs 21

查询#1不是执行此操作的优雅方式...(NOT)IN SELECT适用于少数条目,但它不能以最佳方式使用索引(Seq Scan).

没有EXCEPT,这就是如何编写更有效地使用索引(HASH JOIN).

    SELECT sp.id
    FROM subsource_position AS sp
        LEFT JOIN subsource AS s ON (s.postion_id = sp.id)
    WHERE
        s.postion_id IS NULL
Run Code Online (Sandbox Code Playgroud)


mu *_*ort 7

您的查询在功能上并不相同,因此对其查询计划的任何比较都毫无意义.

根据集理论术语,您的第一个查询是:

{subsource.position_id} - {subsource_position.id}
          ^        ^                ^        ^
Run Code Online (Sandbox Code Playgroud)

但你的第二个是:

{subsource_position.id} - {subsource.position_id}
          ^        ^                ^        ^
Run Code Online (Sandbox Code Playgroud)

而且A - B是不一样的B - A任意套AB.

修复您的查询在语义上等效,然后重试.

  • @RossBradbury那个小编辑会让它更清晰吗? (2认同)

Mag*_*der 6

由于您使用默认配置运行,请尝试增加work_mem.最有可能的是,子查询最终被假脱机到磁盘,因为您只允许1Mb的工作内存.尝试10或20mb.