RANGE分区最适合冷热数据分离,按时间字段连续切分;LIST仅适用于枚举值。RANGE需覆盖全值域且分区键须为主键/唯一键一部分;查询须带分区键才生效;归档优先用EXCHANGE PARTITION;DROP PARTITION不释放磁盘空间,需OPTIMIZE TABLE或重建表。

MySQL分区表怎么选 RANGE 还是 LIST?
冷热数据分离用分区表,RANGE 是最常用也最自然的选择——按时间字段(比如 create_time 或 event_date)切分,老数据进旧分区,新数据自动落新分区。别用 LIST,它适合枚举值(如地区编码、状态码),没法表达“2023年之前”这种连续区间语义。
注意两点:
-
RANGE分区必须覆盖全部可能值,不能留空档;新增分区要用ALTER TABLE ... REORGANIZE PARTITION或提前建好未来几个月的分区 - 分区键必须是主键/唯一键的一部分,否则建表会报错
ERROR 1503 (HY000): A PRIMARY KEY must include all columns in the table's partitioning function - 查询时若
WHERE条件没带上分区键(比如只查status = 'done'而不带时间),MySQL 仍会扫描所有分区,起不到加速效果
归档老数据时,用 ALTER TABLE ... EXCHANGE PARTITION 还是 INSERT INTO ... SELECT?
优先用 EXCHANGE PARTITION,它是秒级操作,本质是元数据交换,不搬数据。但前提是归档目标表(比如 orders_archive)结构、索引、分区定义必须和源分区完全一致,且目标表不能有数据(或先清空)。
常见踩坑点:
- 目标表引擎必须和原表一致(都是
InnoDB),否则报错ERROR 1731 (HY000): Cannot exchange a partition with a table having a different storage engine - 目标表不能有外键约束,也不能被其他表外键引用
- 如果只是临时归档,建议把归档表建在另一个库(如
archive_db),避免和线上库混用,后续清理或备份更可控
分区表删除旧数据后,磁盘空间为什么没释放?
执行 ALTER TABLE ... DROP PARTITION 后,InnoDB 不会立刻归还空间给操作系统,而是留在表空间内供后续插入复用。这是正常行为,不是 bug。
解析 MySQL 8.0 的 DDL 脚本,并将表结构导出为 Excel 格式。适用于用户需将 MySQL 的 `CREATE TABLE` 语句转换为结构化的 Excel 文件场景,导出内容包含字段名、数据类型、长度及精度等信息。支持多张表的批量处理,每张表对应 Excel 中的一个独立工作表。适用于数据库文档编写、数据字典生成及模式分析等任务。
想真正回收磁盘空间,得重建表:
- 对小表:用
OPTIMIZE TABLE orders(本质是ALTER TABLE ... FORCE) - 对大表:用
ALTER TABLE orders ENGINE=InnoDB,并确保innodb_file_per_table=ON(默认开启),这样每个表独立一个.ibd文件,删完分区再重建,文件大小才真实缩小 - 别依赖
TRUNCATE PARTITION——它不存在,MySQL 不支持单独清空分区内容而不删分区
冷数据存到对象存储(如 OSS/S3)前,怎么保证一致性?
MySQL 本身不直接对接对象存储,得靠外部脚本或 ETL 工具中转。关键在于「归档动作」和「业务写入」之间不能有窗口期。
实操建议:
- 归档前先加全局读锁:
FLUSH TABLES orders WITH READ LOCK,记下当前 binlog 位置,归档完再解锁;后续从该位置开始同步到归档库或对象存储 - 更稳妥的做法是停写一小段时间(比如凌晨低峰),用
SELECT ... INTO OUTFILE导出 CSV,再上传到 OSS,并记录导出时的MAX(create_time)作为冷数据边界 - 千万别边写边导出边删——
DELETE FROM orders WHERE create_time 和导出逻辑不同步,极易丢数据
分区表能简化冷热边界管理,但归档链路本身没有原子性,一致性得靠流程卡点和校验兜底。最容易被忽略的是归档后的数据可查性——你删了热库里的行,用户查历史订单时,得有另一套服务去对象存储里捞数据并拼接返回,这部分逻辑不在 MySQL 责任范围内。

















