Postgres - “不存在”比加入慢吗?

Posted

技术标签:

【中文标题】Postgres - “不存在”比加入慢吗?【英文标题】:Postgres - Is "not exists" slower than join? 【发布时间】:2021-02-08 13:40:46 【问题描述】:

我正在尝试查找慢查询的原因,该查询命中 3 个表,记录范围从几十万到几百万不等

探戈 - 6166101 kilo_golf - 822805 three_romeo - 535782

版本

PostgreSQL 11.10

当前查询

select count(*) as aggregate
from "tango"
where "lima" = juliet
  and not exists(select 1
                 from "three_romeo" quebec_seven_oscar
                 where quebec_seven_oscar.six_two = tango.six_two
                   and quebec_seven_oscar."romeo" >= six_seven
                   and quebec_seven_oscar."three_seven" in
                       ('partial_survey', 'survey_completed', 'wrong_number', 'moved'))
  and ("mike" <= '2021-02-03 13:26:22' or "mike" is null)
  and not exists(select 1
                 from "kilo_golf" as "delta"
                 where "delta"."to" = tango.six_two
                   and "two" = november
                   and "delta"."romeo" >= '2021-02-05 13:49:15')
  and not exists(select 1
                 from "three_romeo" as "four"
                 where "four".foxtrot = tango.quebec_seven_victor
                   and "four"."three_seven" in ('deceased', 'block_calls', 'block_all'))
  and "tango"."yankee" is null;

这是当前状态下查询的分析 - https://explain.depesz.com/s/Di51

感觉问题区域在tango表中

tango.lima 在大多数记录中等于“juliet”(基数较低),我们目前没有关于此的索引 长过滤器让我想知道是否应该创建某种复合索引?

在阅读另一篇帖子 (https://***.com/a/50148594/682754) 后,尝试删除 or "mike" is null,这很有帮助

https://explain.depesz.com/s/XgmB

我应该尝试删除不存在以支持使用联接吗?

谢谢

【问题讨论】:

您可以将-infinity 存储在mike 列中,然后您可以摆脱or is null 条件。 【参考方案1】:

我认为使用显式连接不会对您有所帮助,因为 PostgreSQL 无论如何都会将 NOT EXISTS 转换为反连接。

但是您发现了问题:它是OR。我建议您使用动态查询:仅当 mike 不为 NULL 时才添加条件,而不是使用 OR 进行静态查询。

【讨论】:

嗯,我认为是您对链接帖子的回答有助于发现问题;)mike 本质上是一个last_updated 字段,我们希望在几个小时前获得记录 last_updated 或为空。在这种情况下,动态查询适合吗? 当然。仅当 mike 不为 NULL 时才添加条件。 不确定我是否完全遵循...如果我有某种输入允许我添加条件(或不添加),动态查询是否有效。查询的缩短版本是SELECT COUNT(*) FROM people WHERE ("last_loaded" &lt;= '2021-02-03 13:26:22' OR last_loaded IS NULL),我试图在其中获取很久以前加载或尚未加载(NULL)的人。 没有。构成查询的代码类似于if (mike != NULL) append(query_string, "AND last_loaded &lt;= '2021-02-03 13:26:22'";【参考方案2】:

您正在计算大约 600 万行,这需要一些时间。删除or "mike" is null 有很大帮助的原因是它不再需要计算 mike 为空的行,这是其中的绝大多数。

但是,如果您确实需要计算这些行数,这对您毫无用处。你也是?我很难想象在这种情况下,您需要准确计数 600 万行,以至于等待 4 秒是个问题。

【讨论】:

关于计数的好点,我会重新检查它是否真的需要

以上是关于Postgres - “不存在”比加入慢吗?的主要内容,如果未能解决你的问题,请参考以下文章

Postgres:当公共模式上存在表时,关系不存在错误

Postgres:使用 dblink 的“角色不存在”,但确实存在

psql:致命:角色“postgres”不存在

Postgres 列不存在

无法创建用户 postgres:角色“postgres”不存在

角色“postgres”不存在;无法创建用户