结论:存储过程不应实时执行亿级表group by,而应专注参数路由、结果组装与降级控制;聚合计算须交由物化视图或预计算表完成,并确保其索引、刷新策略与字段设计合理。

直接说结论:别在存储过程中实时跑亿级表的 GROUP BY,该用物化视图就用,该建预计算表就建,存储过程只做参数路由和结果组装。
存储过程里写聚合查询,为什么越优化越慢
很多人以为把 COUNT(*)、SUM(amount) 封进存储过程就能提升性能,其实不然。存储过程本身不改变执行计划——它只是把 SQL 包了一层壳。如果底层还是扫全表、没索引覆盖、GROUP BY 字段上用了函数(比如 YEAR(create_time)),那执行计划里照样是 Seq Scan 或 Temporary Table,甚至更糟:因为存储过程常带动态拼接或条件分支,优化器更难做谓词下推。
- MySQL 存储过程中无法使用
PREPARE+EXECUTE动态改执行计划,多数情况会退化为全表扫描 - PostgreSQL 的存储过程若含
RETURN QUERY SELECT ... GROUP BY,且未加STABLE或IMMUTABLE标记,每次调用都重新估算统计信息,可能选错索引 - 一旦存储过程里嵌套多层子查询+聚合,数据库可能放弃合并优化,生成中间临时结果集,内存溢出风险陡增
物化视图怎么嵌进存储过程才不翻车
物化视图不是“加个关键词就能自动加速”的魔法开关。它得和存储过程配合好,否则容易变成数据不一致的源头。
- PostgreSQL 中,必须先给物化视图建唯一索引(如
CREATE UNIQUE INDEX idx_mv_ym ON daily_sales_summary (sale_day, product_id)),才能用REFRESH MATERIALIZED VIEW CONCURRENTLY,否则存储过程调用REFRESH时会锁死整个视图,报表查不到数据 - 不要在存储过程里直接写
REFRESH MATERIALIZED VIEW xxx—— 这会让每次报表请求都触发一次刷新,高并发下 I/O 扛不住;应由调度工具(如 pg_cron)在低峰期定时刷,存储过程只负责SELECT - MySQL 用户请彻底放弃“物化视图”这个词,改用带
ON DUPLICATE KEY UPDATE的预计算表,例如:INSERT INTO rpt_monthly_summary (ym, total_amount) SELECT DATE_FORMAT(create_time,'%Y%m'), SUM(amount) FROM orders WHERE create_time >= ? GROUP BY ym ON DUPLICATE KEY UPDATE total_amount = VALUES(total_amount);
预计算表字段设计与查询路由的关键细节
预计算表不是 GROUP BY 结果导出一张表就完事。字段怎么选、时间戳怎么存、查询时怎么判断走哪条路径,每一步都影响是否真能提速。
- 粒度字段(如
ym、region_id、category_level1)必须设为联合主键或唯一索引,否则INSERT ... ON DUPLICATE KEY UPDATE会失效,导致重复累加 - 务必加
updated_at字段,并在存储过程中加判断逻辑:IF (SELECT MAX(updated_at) FROM rpt_monthly_summary) >= '2024-05-01' THEN SELECT * FROM rpt_monthly_summary WHERE ym BETWEEN '202401' AND '202405'; ELSE SELECT ... FROM orders GROUP BY ...; END IF; - 避免在预计算表里存冗余字段(如把原始订单 ID 列也塞进去),它不再是明细表,而是统计口径的物理快照;字段越多,INSERT/UPDATE 越慢,索引维护成本越高
存储过程真正该干的三件事
高性能报表链路里,存储过程的价值不在“算”,而在“控”和“兜”。它应该轻量、确定、可测。
- 参数校验与标准化:比如把前端传来的
@date_from和@date_to自动转成ym格式,过滤非法值,避免下游 SQL 出现隐式转换 - 路由决策:根据时间范围、租户 ID、业务类型等,决定查物化视图、预计算表,还是降级到原始表(并打监控日志)
- 结果组装与脱敏:把多个预计算表
JOIN后补维度(如地区名称、产品类目),对敏感字段(如用户手机号)做LEFT(encrypt_field, 3)处理,这些逻辑放存储过程里比放应用层更可控
复杂点从来不在语法,而在于你有没有把“什么时候该预计算”“谁负责刷新”“脏数据怎么发现”这些事,在代码之外就定义清楚。否则,再漂亮的 CREATE PROCEDURE 也只是一张没盖章的承诺书。










