【问题标题】:Postgresql huge performance difference when using IN vs NOT IN使用 IN 与 NOT IN 时 Postgresql 的巨大性能差异
【发布时间】:2019-03-09 08:44:09
【问题描述】:

我有 2 张桌子,“transaksi”和“buku”。 “transaksi”大约有 250k 行,buku 大约有 170k 行。两个表都有名为“k999a”的列,并且两个表都没有使用索引。现在我检查这两条语句。

声明 1:

explain select k999a from transaksi where k999a not in (select k999a from buku);

语句 1 输出:

 Seq Scan on transaksi  (cost=0.00..721109017.46 rows=125426 width=9)
   Filter: (NOT (SubPlan 1))
   SubPlan 1
     ->  Materialize  (cost=0.00..5321.60 rows=171040 width=8)
           ->  Seq Scan on buku  (cost=0.00..3797.40 rows=171040 width=8)

声明 2:

explain select k999a from transaksi where k999a in (select k999a from buku);

语句 2 输出:

Hash Semi Join  (cost=6604.40..22664.82 rows=250853 width=9)
   Hash Cond: (transaksi.k999a = buku.k999a)
   ->  Seq Scan on transaksi  (cost=0.00..6356.53 rows=250853 width=9)
   ->  Hash  (cost=3797.40..3797.40 rows=171040 width=8)
         ->  Seq Scan on buku  (cost=0.00..3797.40 rows=171040 width=8)

为什么在NOT IN查询中,postgresql做loop join,使得查询耗时较长?

PS:Windows 10 上的 postgresql 版本 9.6.1

【问题讨论】:

  • 为什么没有索引?
  • 我不知道为什么 Postgres 在一种情况下选择散列 buku,而在另一种情况下在内存中实现 buku。底线是,如果您真的希望这些查询快速运行,您可以在 buku 表中索引 k999a
  • @TimBiegeleisen 对 buku 的索引有何不同?无论如何,他正在对该表进行全面扫描。
  • 我在第一次选择 (select k999a from buku) 时说你得到了一个物化表,你需要整个表来检查 NOT IN 所以在这种情况下索引没有帮助。在第二个中,即使选择看起来也像计划者那样做 SEMI JOIN 在这种情况下索引会有所帮助
  • @JuanCarlosOropeza 刚刚尝试在 buku.k999a 上使用索引,计划没有区别

标签: postgresql sql-execution-plan explain


【解决方案1】:

这是意料之中的。改用WHERE NOT EXISTS 可能会获得更好的性能:

SELECT k999a
FROM transaksi
WHERE NOT EXISTS (
    SELECT 1 FROM buku WHERE buku.k999a = transaksi.k999a LIMIT 1
);

这里很好地解释了每种方法的原因:https://explainextended.com/2009/09/16/not-in-vs-not-exists-vs-left-join-is-null-postgresql/

【讨论】:

  • @TimBiegeleisen - 我可以告诉你,在 PostgreSQL 中肯定不是这种情况。 EXISTSIN 通常是相同的,但对于反连接则不然
  • @TimBiegeleisen - 只有当子选择结果不应为 NULL 时才有可能。 PostgreSQL 无法确保这种行为,然后NOT IN 无法转换为反连接。其他数据库可能可以确保这种行为或其实现在语义上不正确。
  • @Nicarus 基本上,问题是由 postgres 执行 NOT IN 引起的?至少这是我从你提供的链接中得到的
猜你喜欢
  • 1970-01-01
  • 2021-07-25
  • 2011-12-18
  • 2013-02-05
  • 2011-10-30
  • 1970-01-01
  • 1970-01-01
  • 2018-09-28
  • 1970-01-01
相关资源
最近更新 更多