Postgresql Postgres query planner筛选顺序受使用“立即按顺序扫描”影响
我有一个查询,当在postgres数据库上启用顺序扫描并在where子句中使用now()时,查询计划器将倾向于对表进行顺序扫描,然后进行筛选:Postgresql Postgres query planner筛选顺序受使用“立即按顺序扫描”影响,postgresql,query-performance,postgresql-12,Postgresql,Query Performance,Postgresql 12,我有一个查询,当在postgres数据库上启用顺序扫描并在where子句中使用now()时,查询计划器将倾向于对表进行顺序扫描,然后进行筛选: EXPLAIN ANALYZE SELECT action_id FROM events WHERE started_at IS NULL AND deleted_at IS NULL AND due_at < now()
EXPLAIN ANALYZE
SELECT
action_id
FROM
events
WHERE
started_at IS NULL
AND deleted_at IS NULL
AND due_at < now()
AND due_at > now() - interval '14 days'
LIMIT 1
FOR UPDATE
SKIP LOCKED;
但是如果您有其他建议,我们将不胜感激这两个查询都有相同的执行计划 不同之处在于,在从表中仅读取27行之后,带有常量的查询恰好快速找到与条件匹配的行 使用
now()
的查询在表中找不到任何匹配行(actual rows=0
),但它必须扫描所有700万行才能确定
在处的
到期日上的索引应能显著提高性能。两个查询具有相同的执行计划
不同之处在于,在从表中仅读取27行之后,带有常量的查询恰好快速找到与条件匹配的行
使用now()
的查询在表中找不到任何匹配行(actual rows=0
),但它必须扫描所有700万行才能确定
在
处的到期日上的索引应该会大大提高性能。如果使用localtimestamp
而不是now()
?,会发生什么。。。而且发现吵架快多了代码>缓存预热?(无论如何,这张8米长的桌子很可能会放在内存中)@a_horse_与_no_name没有预期的区别。@wildplasser是的,我想你是对的。在两个查询之间执行“放弃所有查询”级别。行估计值为关(800K vs 1)。您有有效的统计数据吗?如果您使用localtimestamp
而不是now()
?。。。而且发现吵架快多了代码>缓存预热?(无论如何,这张8米长的桌子很可能会放在内存中)@a_horse_与_no_name没有预期的区别。@wildplasser是的,我想你是对的。在两个查询之间执行“放弃所有查询”级别。行估计值为关(800K vs 1)。您是否有有效的统计信息?否,扫描将在找到尚未锁定且满足所有条件的行时立即停止。否,不再需要任何时间。也许你的例子不太好,你可以展示一个找到结果但仍然需要很长时间的例子。@Willeman:如果它是一个过滤索引,那么优化器可能更倾向于选择due\u at
上的索引,例如create index on events(due\u at),其中start\u at为null,deleted\u at为null
[顺便说一句:您的单表查询不应该是一个困难的情况。使用正确的数据模型和调整引擎应该选择正确的计划,而不需要任何调整]使用新内容编辑问题或询问新问题。不要忘记解释(分析、缓冲区)
output。不,一旦发现一行尚未锁定且满足所有条件,扫描将立即停止。不,不再需要任何时间。也许您的示例不好,您可以显示一个找到结果但仍然需要很长时间的示例。@Willeman:如果它是作为一个过滤索引,例如,在事件(到期日)上创建索引,其中start\u at为null,deleted\u at为null
[顺便说一句:单表查询应该不是一个困难的情况。使用正确的数据模型和调优,引擎应该选择正确的计划,而不进行任何调整]用新内容编辑问题或提出新问题。不要忘记EXPLAIN(ANALYZE,BUFFERS)
output。
SELECT
id,
previous_event_id,
due_at,
action_id,
subscription_url
FROM (
SELECT
id,
previous_event_id,
due_at,
action_id,
subscription_url from events
WHERE
started_at is null
AND deleted_at is null
LIMIT 100
FOR update SKIP LOCKED
) events_to_pick_from
WHERE EXISTS (
SELECT 1
FROM events
WHERE
events_to_pick_from.due_at < now()
AND events_to_pick_from.due_at > now() - interval '14 days'
AND events.action_id = events_to_pick_from.action_id
)
LIMIT 1
FOR UPDATE SKIP LOCKED;