PostgreSQL:除性能差异外不在与中(编辑2)

PostgreSQL:除性能差异外不在与中(编辑2),sql,postgresql,Sql,Postgresql,我有两个功能相同的查询。其中一个表现很好,另一个表现很差。我看不出性能差异是从哪里产生的 问题1: SELECT id FROM subsource_position WHERE id NOT IN (SELECT position_id FROM subsource) 这将带来以下计划: QUERY PLAN --------------------

我有两个功能相同的查询。其中一个表现很好,另一个表现很差。我看不出性能差异是从哪里产生的

问题1:

SELECT id 
FROM subsource_position
WHERE
  id NOT IN (SELECT position_id FROM subsource)
这将带来以下计划:

                                  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)
问题2:

SELECT id FROM subsource_position
EXCEPT
SELECT position_id FROM subsource;
计划:

我有一种感觉,就是我的一个查询中缺少了一些明显不好的地方,或者我错误地配置了PostgreSQL server。我本以为这不会很好地优化;不总是存在性能问题,或者它没有在这里优化是有原因的吗

其他数据:

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

=> select count(*) from subsource_position;
 count 
-------
 93261
(1 row)
编辑:我现在已经修复了A-B!=B-A下面提到的问题。但我的问题仍然存在:查询1仍然比查询2严重得多。我认为,这是因为两个表的行数相似

编辑2:我正在使用PostgresQL 9.0.4。我无法使用EXPLAIN Analysis,因为查询1花费的时间太长。所有这些列都不是空的,因此不会有任何差异


编辑3:我在这两列上都有索引。我还没有完成查询1,10分钟后我就放弃了。查询2立即返回。

您的查询在功能上并不等价,因此对它们的查询计划进行任何比较都是毫无意义的

用集合论的术语来说,您的第一个查询是:

{subsource.position_id} - {subsource_position.id}
          ^        ^                ^        ^
但你的第二个问题是:

{subsource_position.id} - {subsource.position_id}
          ^        ^                ^        ^
对于任意集合A和B,A-B和B-A是不同的


请将查询修复为语义等效,然后重试。

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

第二个查询使用postgresql的哈希连接功能。这比第一次的Seq扫描快得多。

查询1并不是一种优雅的方式。。。对于一些条目,NOT IN SELECT很好,但它不能使用索引Seq Scan

在拥有之前,除了。。。这是如何使用联接哈希联接完成的:

选择sp.id 从作为sp的子资源位置 在s.position_id=sp.id上以s的形式左连接子源 哪里 s、 职位id为空 除了很久很久以前出现在博士后。。。但例如,使用MySQL,我相信这仍然是使用索引连接实现这一点的唯一方法。

如果id和position\u id都是单独索引的,或者都是多列索引中的第一列索引的,那么只需要两次索引扫描——这是一个基于排序合并的简单集合算法

我个人认为PostgreSQL根本不具备理解这一点的优化智能

我是在诊断了一个运行超过24小时的查询后发现这个问题的,我可以在几秒钟内用sort x y | uniq-u在命令行上执行这个查询。使用pg_转储导出时,数据库小于50MB

附:更有趣的评论:

在优化方面投入了更多的工作 除了和不存在,因为后者实质上是 不太有用,因为它不直观,但规范强制处理空值。 我们不会为此道歉,也不会认为这是一个bug


归根结底,在null处理方面,except与notin是不同的。我没有查看详细信息,但这意味着PostgreSQL没有对其进行优化。

@mu太短了:这正是问题所在。不同的查询语义。你应该回答我,我已经改正了;请再看一看。您需要指定您正在使用的PostgreSQL版本。而且,我不相信这些查询现在也是一样的——考虑空值。最后,你应该经常发布解释分析,而不仅仅是简单的解释。一般来说,不在通常是一个坏主意。这可能就是为什么PostgreSQL有可能是专有的,因为除此之外,我在其他RDBMS中从未听说过它。您并没有说查询是否实际需要不同的时间来执行,或者它是否只是估计的成本,这可能会非常不合理。那么索引呢?@Marian FYI、MS SQL Server和IBM DB2有例外,Oracle有负数。我猜其他数据库也有它们的等价物……我已经更正了SQL和查询计划。如果你能再看一眼的话,我会很感激的。哇,我不得不读了大约5遍,才能看到不同的位置。和uu个字符。@RossBradbury这个小小的编辑能让它更清晰吗?在我的测试中,低至2MB的值就足以解决这个问题。我可能会在两者之间使用一些东西。谢谢你的帮助!性能差异与服务器配置无关。这两个查询使用索引的能力或限制不同。1=>需要逐个扫描子源中的所有条目,2可以获得两个索引以进行内部匹配哈希连接。但好的,为扫描表添加更多的工作内存
in-RAM可以帮助运行非常糟糕的SQL而不使用连接…这是否意味着“not-in”不能使用索引?这是一个多么好的主意!
{subsource_position.id} - {subsource.position_id}
          ^        ^                ^        ^