一、分区表基础:从一张大表说起
先问大家一个问题:你手头有一张 10TB 的订单表,每天要查最近 7 天的数据,还要按月做统计报表。这张表索引建了、SQL 也优化了,可查询还是慢得像蜗牛。怎么办?
我早年在一家电商公司就遇到过这事。当时 DBA 团队想了各种办法,最后靠分区表解决了问题。说白了,分区表就是把一张大表拆成多个小表,但对应用层透明——你查的还是那张表,数据库自动帮你定位到正确的分区。
1.1 什么是表分区
表分区是一种物理存储层面的拆分技术。它把一张表的数据,按照某个规则(比如时间、地区、ID 范围)分散到不同的物理段中。每个段叫一个分区,分区可以独立管理、独立备份、独立查询。
举个例子,一张订单表按月份分区:
CREATE TABLE orders (
order_id BIGINT,
order_date DATE,
customer_id INT,
amount DECIMAL(10,2)
)
PARTITION BY RANGE (YEAR(order_date), MONTH(order_date)) (
PARTITION p202401 VALUES LESS THAN (2024, 2),
PARTITION p202402 VALUES LESS THAN (2024, 3),
PARTITION p202403 VALUES LESS THAN (2024, 4),
PARTITION p_future VALUES LESS THAN MAXVALUE
);
你看,数据按年月自动落入对应分区。查询时如果带上 order_date 条件,数据库直接跳过无关分区——这就是分区裁剪的核心。
核心概念:分区裁剪(Partition Pruning)是指查询优化器根据 WHERE 条件,只扫描匹配的分区,忽略不相关的分区。这是分区表性能提升的根本来源。
1.2 分区表的优势
我总结下来,分区表有四大好处:
| 优势 | 说明 | 我见过的场景 |
|---|---|---|
| 查询性能提升 | 只扫描相关分区,减少 I/O | 某金融系统月报查询从 45 秒降到 3 秒 |
| 管理更灵活 | 可单独备份、重建、压缩某个分区 | 历史数据归档时只操作旧分区,不影响在线业务 |
| 数据清理高效 | 直接 TRUNCATE 分区,比 DELETE 快百倍 | 日志表保留 90 天,到期直接删分区 |
| 并行能力增强 | 多分区可并行扫描 | 大数据量聚合查询,分区并行后吞吐翻倍 |
嗯,这里要注意:分区表不是银弹。如果查询条件不带分区键,反而可能比普通表更慢——因为优化器要扫描所有分区的元数据。
1.3 适用场景
我个人习惯把适用场景分成三类:
- 时间序列数据:日志、订单、交易流水。这类数据天然按时间增长,查询也常带时间范围。
- 大表数据归档:比如保留最近 3 个月数据,历史数据移到冷分区。我曾经帮一个客户把 5TB 的审计表按月分区,清理效率提升了 20 倍。
- 按地域或业务线拆分:比如按省份分区,查询时只扫本省数据。
我的建议:表数据量超过 500GB,或者单表行数超过 1 亿,就可以考虑分区。小于这个量级,分区带来的管理成本可能超过收益。
1.4 分区键的选择原则
分区键选错了,分区表就废了。我踩过这个坑——曾经按订单状态分区,结果 90% 的数据都在「已完成」分区,其他分区几乎空着。这叫分区倾斜,性能还不如不分区。
选分区键,记住三条原则:
- 高频查询条件:分区键必须是 WHERE 子句里最常用的字段。你想想看,如果查询很少带分区键,分区裁剪就失效了。
- 数据分布均匀:每个分区的数据量要差不多。避免某个分区特别大,其他分区特别小。
- 分区数量适中:分区太多(比如上千个)会导致元数据膨胀,DDL 操作变慢。我一般建议控制在 50~200 个分区。
举个例子,订单表按 order_date 分区就比按 order_status 好——时间天然均匀分布,而且查询常带时间范围。
避坑指南:我曾经见过有人用 UUID 做分区键,结果每个分区数据量完全随机,查询时几乎要扫描所有分区。分区键一定要有业务意义,且查询模式可预测。
1.5 分区表的知识体系
下面这张图帮你理清分区表的核心脉络:
1.6 小结
分区表的核心就一句话:把大表拆小,让查询只扫该扫的数据。选对分区键,分区裁剪才能生效。我见过太多人分区键选错了,最后分区表反而成了性能瓶颈。