分区聚合需group by维度与分区键对齐并触发分区裁剪;错误示例中date()函数导致全表扫描,正确写法是where条件直接裸露引用分区键列,如order_date >= '2024-01-01'。

直接上结论:分区聚合不是“先分区再聚合”,而是让聚合逻辑天然适配分区结构——核心是把 GROUP BY 的维度和分区键对齐,并确保查询能触发分区裁剪(Partition Pruning),否则聚合仍会扫全表。
为什么用分区做聚合反而更慢?
常见错误是建了按 order_date 分区的表,但聚合时写 SELECT COUNT(*) FROM orders WHERE DATE(order_date) = '2024-01-01' GROUP BY status。这里用了 DATE() 函数,导致优化器无法识别分区键原始值,partitions: all 就出现了。
真正起效的前提只有一个:WHERE 条件必须**直接、裸露地引用分区键列**,且不加任何函数或表达式。
- ✅ 正确:
WHERE order_date >= '2024-01-01' AND order_date - ❌ 无效:
WHERE YEAR(order_date) = 2024 AND MONTH(order_date) = 1 - ❌ 无效:
WHERE DATE(order_date) = '2024-01-01'
聚合字段必须包含分区键吗?
不一定,但强烈建议在索引和聚合逻辑中显式带上。比如你要按 tenant_id + status 聚合,而表是按 tenant_id 分区的,那最优写法是:
SELECT tenant_id, status, COUNT(*)
FROM orders
WHERE tenant_id IN ('t-001', 't-002')
GROUP BY tenant_id, status
这样不仅触发分区裁剪(只查两个分区),还能利用本地索引(如 LOCAL INDEX (tenant_id, status))避免回表。如果去掉 tenant_id 在 GROUP BY 中,即使 WHERE 里写了,优化器也可能选择全分区扫描后再合并结果。
- 分区键进
GROUP BY是显式告诉优化器:“我只要这几个分区里的分组” - 若业务允许,优先把分区键作为聚合的第一层维度(例如先按年,再按月,再按状态)
- 跨分区聚合(如全量统计所有租户的订单数)永远比单分区聚合慢——这不是分区的问题,是需求本身决定的
如何验证聚合真的只扫了目标分区?
别信 DDL,要看执行计划。不同数据库命令不同,但关键字段一致:
- MySQL:用
EXPLAIN PARTITIONS SELECT ...,检查输出中的partitions列是否只列出预期分区(如p202401,p202402),而非all - PostgreSQL:用
EXPLAIN (ANALYZE, BUFFERS) SELECT ...,看Partition Filter是否命中,以及Actual Partitions数量 - SQL Server:用
SET STATISTICS XML ON,在执行计划中找PartitionCount和Actual Partition Count
一个容易被忽略的点:即使你写了正确条件,如果统计信息过期(ANALYZE 或 UPDATE STATISTICS 没跑),优化器仍可能误判并放弃裁剪。定期更新统计信息不是可选项,是分区表上线后的必做动作。










