大查询拆分需分阶段计算并缓存中间结果。先识别高开销及复用子查询,如销售报表中“区域+产品线+日粒度汇总”作为Stage 1宽表;Stage 2轻量加工;Stage 3仅过滤排序。优先用带注释的持久化中间表而非CTE,配索引、血缘管理与校验,实测端到端性能。

大查询拆分不是简单地把一个SQL切开,而是围绕“减少单次计算压力”和“复用中间结果”来设计执行路径。核心是分阶段计算 + 缓存(临时表或物化视图),让重复依赖的数据只算一次、多处复用。
明确阶段边界:从逻辑依赖出发
先画出报表的计算链条,识别哪些子查询被多次引用、哪些步骤I/O或CPU开销高。例如:某销售报表需按区域、产品线、时间三个维度聚合,再计算同比、完成率、TOP10排名——其中“区域+产品线+日粒度销售汇总”是所有指标的基础,应作为第一阶段固化下来。
- 基础层(Stage 1):生成宽表或汇总快照,如 tmp_sales_daily_agg,带索引,保留必要字段(region_id, prod_line, sale_date, amount, order_cnt)
- 计算层(Stage 2):基于Stage 1做轻量级加工,如加窗口函数算累计、LAG算同比,避免重复JOIN和GROUP BY
- 展示层(Stage 3):仅做过滤、排序、分页,不涉及聚合或关联
缓存策略选型:临时表 vs 持久化中间表
临时表适合单次会话内复用,速度快但不可跨作业;中间表适合T+1调度场景,支持重跑、监控和权限管控。别盲目用CTE——它只是语法糖,多数数据库仍会重复执行。
- 用 CREATE TEMP TABLE 做调试和小批量验证,注意生命周期(会话结束自动销毁)
- 生产环境优先建带注释的中间表,命名带业务前缀和日期标识,如 mid_sales_agg_d20240615
- 对高频访问的中间结果,加合适索引(如 (region_id, sale_date) 覆盖常用WHERE+ORDER)
- 定期清理过期中间表,避免磁盘膨胀
分阶段调度与血缘管理
拆分后各阶段变成独立可调度单元,必须显式定义依赖关系。否则Stage 2可能读到Stage 1未写完或脏数据。
- 用调度工具(Airflow/DolphinScheduler)配置上下游任务依赖,强制Stage 1成功后再触发Stage 2
- 在中间表里加 etl_batch_id 和 etl_time 字段,便于追踪数据版本和问题回溯
- 关键中间表增加校验任务:行数波动超阈值、空值率突增、主键重复等,失败即告警
性能对比要测真实负载
别只看执行计划里的“cost”,要测端到端耗时、内存峰值、磁盘IO和并发影响。同一查询拆分前后,在相同数据量、相同并发压力下对比。
- 原始大SQL:可能占用大量shared_buffers,阻塞其他查询
- 分阶段方案:Stage 1耗时长但只跑一次,Stage 2~3响应快、资源占用低,整体吞吐更高
- 观察缓存命中率:若Stage 1结果被多个报表共用,ROI更明显










