You need to enable JavaScript to run this app. PostgreSQL如何高效统计不同日期对应的多类事件发生次数
优惠活动
大模型
产品
解决方案
定价
更多

PostgreSQL如何高效统计不同日期对应的多类事件发生次数

原SQL性能问题原因

原写法使用了相关子查询,外层每返回一个日期就要全表扫描一次deals表做匹配,时间复杂度为O(n²),数据量上升后耗时会大幅增长,核心优化思路是将多次表扫描简化为1次。

优化实现方案

方案1:通用高兼容写法(支持所有主流数据库,复杂度O(n))

仅需扫描1次deals表即可完成所有统计,扩展性强,后续新增时间类型统计只需修改对应逻辑:

SELECT
    change_datetime,
    SUM(add_flag) AS add_time_count,
    SUM(last_mail_flag) AS last_mail_count,
    SUM(lost_flag) AS lost_time_count
FROM (
    SELECT add_time::date AS change_datetime, 1 AS add_flag, 0 AS last_mail_flag, 0 AS lost_flag FROM deals WHERE add_time IS NOT NULL
    UNION ALL
    SELECT last_mail_time::date AS change_datetime, 0 AS add_flag, 1 AS last_mail_flag, 0 AS lost_flag FROM deals WHERE last_mail_time IS NOT NULL
    UNION ALL
    SELECT lost_time::date AS change_datetime, 0 AS add_flag, 0 AS last_mail_flag, 1 AS lost_flag FROM deals WHERE lost_time IS NOT NULL
) AS t
GROUP BY change_datetime
ORDER BY change_datetime;

方案2:现代数据库简化写法(支持PostgreSQL/MySQL 8.0+/SQL Server)

用枚举事件的方式进一步简化代码,逻辑更清晰:

SELECT
    event_date AS change_datetime,
    SUM(CASE WHEN event_type = 'add' THEN 1 ELSE 0 END) AS add_time_count,
    SUM(CASE WHEN event_type = 'mail' THEN 1 ELSE 0 END) AS last_mail_count,
    SUM(CASE WHEN event_type = 'lost' THEN 1 ELSE 0 END) AS lost_time_count
FROM deals
CROSS JOIN (
    VALUES 
        ('add', add_time::date),
        ('mail', last_mail_time::date),
        ('lost', lost_time::date)
) AS event_map(event_type, event_date)
WHERE event_date IS NOT NULL
GROUP BY event_date
ORDER BY event_date;
额外性能优化建议
  • 可针对三个时间字段创建函数索引,以PostgreSQL为例:CREATE INDEX idx_deals_add_time_date ON deals((add_time::date));,高频统计场景下查询速度会进一步提升
  • 若只需统计特定时间范围的数据,可在内层子查询的WHERE条件中添加时间过滤规则,减少扫描的数据量

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.16 00:36:04