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
表中
在阅读另一篇帖子 (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" <= '2021-02-03 13:26:22' OR last_loaded IS NULL)
,我试图在其中获取很久以前加载或尚未加载(NULL)的人。
没有。构成查询的代码类似于if (mike != NULL) append(query_string, "AND last_loaded <= '2021-02-03 13:26:22'";
【参考方案2】:
您正在计算大约 600 万行,这需要一些时间。删除or "mike" is null
有很大帮助的原因是它不再需要计算 mike 为空的行,这是其中的绝大多数。
但是,如果您确实需要计算这些行数,这对您毫无用处。你也是?我很难想象在这种情况下,您需要准确计数 600 万行,以至于等待 4 秒是个问题。
【讨论】:
关于计数的好点,我会重新检查它是否真的需要以上是关于Postgres - “不存在”比加入慢吗?的主要内容,如果未能解决你的问题,请参考以下文章
Postgres:使用 dblink 的“角色不存在”,但确实存在