MySQL 分区表(PARTITION)实践示例
下面我将给你一个完整、可操作、详细的 MySQL 分区表示例,通过一个用户表按时间范围分区的案例,帮助你快速理解和使用 MySQL 原生的分区功能。
🎯 一、什么是 MySQL 分区表(Partitioning)
MySQL 的 分区表(Partitioned Table) 允许你将一个大表在物理上分成多个分区 ,但对应用来说仍然是一张表。MySQL 会自动管理数据应该存储在哪个分区中。
- ✅ 对应用透明:你仍然操作的是一张表,不需要关心数据在哪个分区
- ✅ 提升查询性能:查询时可只扫描相关分区
- ✅ 便于管理:可以单独备份、删除某个分区的数据
- ❌ 不是分库分表:所有分区仍然在同一个数据库实例中
- ❌ 功能有限:比如不支持外键、某些存储引擎和功能受限
📦 二、实用示例:用户登录记录表按时间范围分区
🎪 场景
假设我们有一张用户登录记录表 user_logins
,记录用户每次登录的时间和IP等信息。随着时间推移,这张表会变得非常大,但我们往往只关心最近几个月的数据。
我们可以按登录时间(月份)进行范围分区,比如每个月一个分区,便于管理和查询。
🛠️ 三、创建按时间范围分区的表
1. 创建按 RANGE 分区的表(按月份)
sql
CREATE TABLE user_logins (
id BIGINT NOT NULL AUTO_INCREMENT,
user_id INT NOT NULL,
login_time DATETIME NOT NULL,
ip_address VARCHAR(45),
device_info VARCHAR(255),
PRIMARY KEY (id, login_time) -- 注意:分区字段必须包含在主键中
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
PARTITION BY RANGE (YEAR(login_time) * 100 + MONTH(login_time)) (
PARTITION p202301 VALUES LESS THAN (202302),
PARTITION p202302 VALUES LESS THAN (202303),
PARTITION p202303 VALUES LESS THAN (202304),
PARTITION p202304 VALUES LESS THAN (202305),
PARTITION p202305 VALUES LESS THAN (202306),
PARTITION p_max VALUES LESS THAN MAXVALUE -- 未来日期放到这个分区
);
🔍 关键点解释:
- 使用
PARTITION BY RANGE (...)
定义按范围分区- 分区表达式:
YEAR(login_time) * 100 + MONTH(login_time)
→ 202301 表示 2023年1月- 每个分区用
PARTITION p202301 VALUES LESS THAN (202302)
定义p_max
是一个"兜底"分区,存放超过定义范围的数据- 注意:主键或唯一索引中必须包含分区字段(这里是 login_time)
2. 简化版:按 YEAR(login_time) 分区(按年)
如果你觉得按月太细,也可以按年分区,更简单:
sql
CREATE TABLE user_logins_simple (
id BIGINT NOT NULL AUTO_INCREMENT,
user_id INT NOT NULL,
login_time DATETIME NOT NULL,
ip_address VARCHAR(45),
PRIMARY KEY (id, login_time)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
PARTITION BY RANGE (YEAR(login_time)) (
PARTITION p2021 VALUES LESS THAN (2022),
PARTITION p2022 VALUES LESS THAN (2023),
PARTITION p2023 VALUES LESS THAN (2024),
PARTITION p_future VALUES LESS THAN MAXVALUE
);
🧪 四、插入数据和查询(验证分区效果)
插入测试数据
sql
-- 插入 2023年1月的数据
INSERT INTO user_logins (user_id, login_time, ip_address)
VALUES (1, '2023-01-15 10:00:00', '192.168.1.1');
-- 插入 2023年3月的数据
INSERT INTO user_logins (user_id, login_time, ip_address)
VALUES (2, '2023-03-20 14:30:00', '10.0.0.2');
-- 插入 2024年1月的数据(会进入 p_future 分区)
INSERT INTO user_logins (user_id, login_time, ip_address)
VALUES (3, '2024-01-10 08:00:00', '172.16.0.1');
查询数据(MySQL 会自动路由到对应分区)
sql
-- 查询某个用户的所有登录记录(自动扫描相关分区)
SELECT * FROM user_logins WHERE user_id = 1;
-- 查询 2023年3月的登录记录
SELECT * FROM user_logins
WHERE login_time >= '2023-03-01' AND login_time < '2023-04-01';
✅ 即使你没有显式指定分区,MySQL 也会根据
login_time
的值自动选择对应的分区进行查询,提高效率!
🛠️ 五、查看分区信息
查看表的分区定义
sql
SHOW CREATE TABLE user_logins;
查看表有哪些分区,以及每分区有多少数据
sql
SELECT
PARTITION_NAME,
PARTITION_ORDINAL_POSITION,
TABLE_ROWS,
PARTITION_EXPRESSION,
PARTITION_DESCRIPTION
FROM
INFORMATION_SCHEMA.PARTITIONS
WHERE
TABLE_SCHEMA = '你的数据库名' AND
TABLE_NAME = 'user_logins';
📌 你可以看到每个分区叫什么(如 p202301)、存了多少行数据、范围是什么等。
🔄 六、管理分区(重要!)
1. 添加新分区(比如为下个月添加 p202306)
sql
ALTER TABLE user_logins
ADD PARTITION (
PARTITION p202306 VALUES LESS THAN (202307)
);
2. 删除旧分区(比如删掉 2023年1月的数据)
sql
ALTER TABLE user_logins
DROP PARTITION p202301;
⚠️ 注意:
DROP PARTITION
会直接删除整个分区的数据,不可恢复!慎用!
3. 合并/拆分分区(高级用法,较少用)
✅ 七、什么时候适合使用 MySQL 分区表?
适用场景 | 说明 |
---|---|
📈 数据量大,但可以按时间/范围清理 | 比如日志、订单、用户行为记录,可以按月份/年份分区,定期删掉旧分区 |
🚀 查询经常按分区字段过滤 | 如 WHERE login_time BETWEEN ... ,MySQL 可只查相关分区,提高性能 |
🗃️ 希望快速删除大量历史数据 | 直接 DROP PARTITION 比 DELETE 快很多,且不产生大量 undo 日志 |
🧹 希望按周期归档或备份某个时间段的数据 | 可以单独备份或导出某个分区 |
不适用场景 | 说明 |
----------- | ------ |
❌ 需要外键约束 | 分区表不支持外键 |
❌ 需要某些高级功能(如全文索引等) | 部分功能受限 |
❌ 想实现真正的"分库分表"、分布式存储 | 分区表仍然在同一个数据库实例中 |
📝 总结 & 动手建议
✅ 你可以马上尝试的实践:
- 创建一个测试数据库和表 ,如
user_logins
,按月份或年份做 RANGE 分区 - 插入一些带时间的数据,覆盖多个分区
- 执行查询,观察是否高效
- 查看分区信息 :
SHOW CREATE TABLE
和INFORMATION_SCHEMA.PARTITIONS
- 尝试添加/删除分区,体验分区管理
🧠 关键要点:
- 分区表是 MySQL 原生支持的、对应用透明的"大表拆分物理存储"方案
- 分区字段要合理选择(通常是时间、地区等有范围的字段)
- 主键/唯一索引必须包含分区字段
- 适合做冷热数据分离、定期删除、提高查询效率
- 不是分库分表,数据仍在同一个 MySQL 实例中