为什么PostgreSQL不在“WHERE NOT IN”条件下使用索引。

为什么PostgreSQL不在“WHERE NOT IN”条件下使用索引。,postgresql,Postgresql,我有两个表db100和db60,它们具有相同的字段:x,y,z。 为字段z上的两个表创建索引,如下所示: CREATE INDEX db100_z_idx ON db100 USING btree (z COLLATE pg_catalog."default"); CREATE INDEX db60_z_idx ON db60 USING btree (z COLLATE pg_catalog."default"); 试图从db60中查找db100中不存在的z值: se

我有两个表db100和db60,它们具有相同的字段:x,y,z。 为字段z上的两个表创建索引,如下所示:

CREATE INDEX db100_z_idx
  ON db100
  USING btree
  (z COLLATE pg_catalog."default");
CREATE INDEX db60_z_idx
  ON db60
  USING btree
  (z COLLATE pg_catalog."default");
试图从db60中查找db100中不存在的z值:

select db60.z from db60 where db60.z not in (select db100.z from db100)
据我所知,执行查询所需的所有信息都显示在索引中。因此,我希望只使用索引。 但是,它对表使用顺序扫描:

"Seq Scan on db60  (cost=0.00..25951290012.84 rows=291282 width=4)"
"  Filter: (NOT (SubPlan 1))"
"  SubPlan 1"
"    ->  Materialize  (cost=0.00..80786.26 rows=3322884 width=4)"
"          ->  Seq Scan on db100  (cost=0.00..51190.84 rows=3322884 width=4)"
有人能解释一下为什么PostgreSQL在这个例子中不使用索引吗

这两个表都包含数百万条记录,执行需要一段时间

我知道使用带is null条件的左连接可以得到更好的结果。然而,问题是关于这个特殊的语法

我在PgV9.5上,子计划1用于从db100中选择db100.z。您选择了所有行,因此索引是无用的。您确实希望在这里从db100中选择DISTINCT z,然后应该使用索引

在主查询中,您已经从db60中选择了db60.z,其中db60.z不在。。。。再次选择除条件为非真的行之外的所有行,因此索引同样不适用,因为它适用于反向条件

通常,只有当计划人员认为索引的使用会加速查询处理时,才使用索引。它始终取决于有多少不同的值,以及行如何分布在磁盘上的物理页上。用于搜索具有某个值的列的所有行的索引与查找不具有该值的行的索引不同;索引指示在哪些页面上以及在哪些位置查找行,但该集合不能简单地反转

在你的例子中,如果z是某种文本类型,就不能构造一个有意义的负索引,这实际上几乎是一个真正的ism,尽管在某些情况下负索引是可以想象的。您应该深入研究,因为它们在文本索引方面的工作速度往往比btree快得多


您真的想提取所有具有相同z值的291282行,或者在这里使用DISTINCT子句?这将大大加快速度。

请使用explain Analyzer添加计划z字段显然是一个varchar或其变体。z的典型值是什么?具体来说,这些值可以是长字符串吗?是的,两个表中都有许多重复的z值。嗯,添加distinct确实大大减少了处理时间。然而explain仍然不显示索引的使用:HashAggregate cost=70677.28..70694.77 rows=1749 width=4组键:db60.z->db60上的Seq Scan cost=59518.04..69949.07 rows=291282 width=4 Filter:NOT hashed SubPlan 1 SubPlan 1->HashAggregate cost=59498.05..59514.04 rows=1599 width=4组键:db100.z->db100上的顺序扫描成本=0.00..51190.84行=3322884宽度=4@spoonboy:不要在注释中添加代码。你应该向我们展示解释分析的输出,而不是简单的解释