在mysql中,当业务数据按时间持续累积时,单张表很容易变得庞大,导致查询变慢、备份困难。利用分区表功能,我们可以在同一张逻辑表下按月份做物理拆分,这就是常说的按月分表。mysql的分区表对外看起来是一张表,内部却按规则分散存储,查询时若能命中分区条件,性能会明显提升。

什么是mysql分区表
分区表是指根据指定规则,将表的数据分布到不同的分区中。对应用来说,依然操作同一张表,但底层数据被切分。mysql支持range、list、hash、key等分区类型,其中range分区最适合按时间按月分表。
如何用range分区实现按月分表
通常我们会用一个日期或时间类型的字段,比如create_time,按月份进行range分区。下面示例创建一张订单表,按月份分区:
CREATE TABLE orders (
id BIGINT NOT NULL,
user_id INT NOT NULL,
amount DECIMAL(10,2) NOT NULL,
create_time DATE NOT NULL
)
PARTITION BY RANGE (TO_DAYS(create_time)) (
PARTITION p202401 VALUES LESS THAN (TO_DAYS('2024-02-01')),
PARTITION p202402 VALUES LESS THAN (TO_DAYS('2024-03-01')),
PARTITION p202403 VALUES LESS THAN (TO_DAYS('2024-04-01')),
PARTITION pmax VALUES LESS THAN MAXVALUE
);
这里使用TO_DAYS()函数将日期转为天数,每个分区存放小于下个月一号的数据,从而实现按月切割。
如何新增和删除月份分区
随着时间推移,需要增加新月份分区,并清理过期数据。直接drop分区比delete快很多,且不产生大量碎片。
-- 新增2024年4月分区
ALTER TABLE orders
ADD PARTITION (PARTITION p202404 VALUES LESS THAN (TO_DAYS('2024-05-01')));
-- 删除2024年1月旧分区
ALTER TABLE orders DROP PARTITION p202401;
如何利用分区优化查询性能
分区表优化查询的核心是分区裁剪。当where条件包含分区键时,mysql只扫描相关分区。
-- 只会访问p202402分区 SELECT * FROM orders WHERE create_time >= '2024-02-01' AND create_time < '2024-03-01';
如果查询不带create_time条件,则会扫描全部分区,此时优势消失。因此业务查询应尽量带上时间范围。
注意事项
- 分区键必须是主键或唯一索引的一部分,否则建表会报错。
- 单表分区数不宜过多,通常几百以内较安全。
- 分区表不支持外键,跨分区查询仍可能较慢。
总结
利用mysql的range分区按月份分表,是一种低侵入、易维护的优化手段。它让数据按时间自然归档,查询时通过分区裁剪减少IO,删除旧数据时也能快速完成。实际使用中只需在建表时规划好分区规则,并确保在查询中带上分区字段即可显著提升性能。