You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何`date_trunc('day', current_date)+interval...`会导致PostgreSQL查询挂起?

PostgreSQL查询使用当天结束时间作为范围上限时无限挂起的原因分析

核心问题:子查询返回行数的巨大差异

两个range_values子查询的本质区别在于返回的结果行数:

  • 第一个子查询使用max(lasttime)聚合函数,会对people表做聚合计算,最终仅返回1行结果。
  • 第二个子查询没有任何聚合操作,只是从people表中查询两个与表行无关的常量值(date_trunc('month', current_date)和当天结束时间都是固定值),这会导致子查询返回与people表总行数完全一致的结果集。

如果people表数据量较大(比如几十万甚至百万行),第二个子查询会生成海量重复的minval和maxval记录,后续查询基于这个超大结果集进行关联、过滤时,会产生指数级的计算量,直接导致查询无限挂起。

验证方式

单独运行第二个子查询,查看返回行数:

select date_trunc('month', current_date) as minval,
    (date_trunc('day', current_date) + interval '1 day' - interval '1 second') as maxval
from people;

结果行数会等于people表的总行数,所有行的内容完全相同。

解决办法

将第二个子查询修改为仅返回单行结果,以下几种方式均可:

  1. 添加聚合函数(利用聚合函数将多行合并为单行):
range_values as (
    select date_trunc('month', current_date) as minval,
        max(date_trunc('day', current_date) + interval '1 day' - interval '1 second') as maxval
    from people
)
  1. 使用单行数据源(避免从大表查询常量值):
range_values as (
    select date_trunc('month', current_date) as minval,
        (date_trunc('day', current_date) + interval '1 day' - interval '1 second') as maxval
    from (select 1) as t
)
  1. 添加limit 1限制行数:
range_values as (
    select date_trunc('month', current_date) as minval,
        (date_trunc('day', current_date) + interval '1 day' - interval '1 second') as maxval
    from people
    limit 1
)

补充说明

另外,end_of_day的范围比max(lasttime)大,若后续查询基于该范围过滤数据,可能会扫描更多索引或数据块,但最根本的性能瓶颈还是子查询返回的行数过多。

内容的提问来源于stack exchange,提问作者3ch01c

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 15:40:37