第 17 章
分区表实战
MySQL 分区表完全指南
分区将大型表分成较小的、更易于管理的部分。这提高了查询性能,启用了有效的归档,并为有数百万行的表简化了维护。
1. 分区类型
RANGE分区(最常见):
CREATE TABLE orders (
id INT,
order_date DATE
) PARTITION BY RANGE (YEAR(order_date)) (
PARTITION p2020 VALUES LESS THAN (2021),
PARTITION p2021 VALUES LESS THAN (2022),
PARTITION p2023 VALUES LESS THAN (2024),
PARTITION pmax VALUES LESS THAN MAXVALUE
);
优势:
├─ 查询只扫描相关分区
├─ 删除旧数据:DROP PARTITION(毫秒级)
├─ 易于维护:按日期管理数据
LIST分区:
按列表值分配(如:国家代码)
HASH分区:
均匀分布(用于并行,不用于剪枝)
2. 分区维护
添加分区:
ALTER TABLE orders ADD PARTITION (
PARTITION p2024 VALUES LESS THAN (2025)
);
删除分区(秒级):
ALTER TABLE orders DROP PARTITION p2020;
传统DELETE对比:
DELETE FROM orders WHERE YEAR(order_date) = 2020;
├─ 耗时:数分钟(百万级行数)
├─ 日志:撤销日志+重做日志
└─ 影响:锁定写入,占用内存
DROP PARTITION对比:
├─ 耗时:毫秒(元数据操作)
├─ 日志:最小
└─ 影响:无
3. 分区剪枝
分区剪枝:查询优化器跳过无关分区
常数条件(MySQL所有版本):
SELECT * FROM orders WHERE order_date >= '2023-01-01';
├─ 只扫描:p2023, pmax
└─ 跳过:p2020, p2021, p2022
验证剪枝:
EXPLAIN SELECT * ... WHERE order_date >= '2023-01-01'\G
partitions列显示:p2023, pmax ✓
INFORMATION_SCHEMA:
SELECT PARTITION_NAME, PARTITION_DESCRIPTION
FROM INFORMATION_SCHEMA.PARTITIONS
WHERE TABLE_NAME = 'orders';
4. 限制与注意事项
唯一约束:
唯一键必须包含分区键!
❌ 错误:
CREATE TABLE orders (
id INT UNIQUE,
order_date DATE
) PARTITION BY RANGE (YEAR(order_date)) (...);
-- 错误:无分区键的唯一约束!
✓ 正确:
CREATE TABLE orders (
id INT,
order_date DATE,
UNIQUE (id, order_date) -- 包含分区键
) PARTITION BY RANGE (YEAR(order_date)) (...);
外键:
❌ 分区表不能作为外键父表
❌ 分区表引用外键(支持有限)
全文索引:
❌ 分区表不支持
空间索引:
❌ 分区表不支持
4. 实际应用:时间序列数据
场景:10亿行日志表,按日期分区
CREATE TABLE logs (
id BIGINT AUTO_INCREMENT,
timestamp DATETIME,
data TEXT,
PRIMARY KEY (id, timestamp)
) PARTITION BY RANGE (TO_DAYS(timestamp)) (
PARTITION p_day_1 VALUES LESS THAN (738000),
...(365日分区)
PARTITION p_max VALUES LESS THAN MAXVALUE
);
优势:
日志删除:
ALTER TABLE logs DROP PARTITION p_day_1;
├─ 速度:毫秒级
└─ 传统DELETE:数小时
查询优化:
SELECT * FROM logs WHERE timestamp >= '2024-01-01';
├─ 扫描:~31分区(1月份)
├─ 跳过:~334分区
└─ 性能:8%的全表扫描时间
自动管理:
Cron每天添加新分区
6. 分区 vs 分片
分区(单服务器):
├─ 所有数据在一个MySQL实例
├─ MySQL自动处理(透明)
├─ 与非分区表相同SQL
└─ 受服务器资源限制
分片(多服务器):
├─ 数据分布在多个实例
├─ 手动应用逻辑
├─ 每分片不同查询
└─ 水平扩展超越单服务器
何时使用分区:
├─ 表适合单服务器存储
├─ 读/写QPS单服务器可处理
└─ 运维复杂度可接受
何时使用分片:
├─ 数据超过单服务器容量
├─ QPS超过单服务器能力
├─ 需要高可用
└─ 需要全球分布
5. 最佳实践
- ✓ 选择合适的分区键——影响剪枝效率
- ✓ 使用基于日期的分区——最常见且有效
- ✓ 设置MAXVALUE分区——捕捉意外值
- ✓ 自动化分区管理——Cron作业添加/删除
- ✓ 监控分区大小——确保均匀分布
- ✗ 不要分区小表——开销超过收益
- ✗ 不要后期添加分区——迁移困难
- ✓ 与索引配合——分区+索引=最佳性能
总结
分区适合管理非常大的表(>10GB),特别是时间序列数据。基于日期的每日或每月分区通常效果最好。自动化分区生命周期管理以避免手动开销。