mysqldump 默认导出分区表时包含 PARTITION BY 子句,但需警惕 MySQL ≥ 8.0.27 的 ALGORITHM=INSTANT 元数据不完整及权限不足导致分区定义被跳过或报错 ERROR 1227。

mysqldump 无法直接保留分区定义,必须显式启用 --include-definer 和 --no-create-info 组合?
不是。mysqldump 默认导出分区表时会包含 PARTITION BY 子句,但有两个关键陷阱:一是若源库 MySQL 版本 ≥ 8.0.27 且使用了 ALGORITHM=INSTANT 分区操作,部分元数据可能不完整;二是如果目标库禁用 log_bin_trust_function_creators 或用户权限不足,CREATE TABLE 语句中的分区定义可能被跳过或报错 ERROR 1227 (42000): Access denied; you need (at least one of) the SUPER privilege(s) for this operation。
实操建议:
- 始终用
mysqldump --no-data --routines --triggers --events单独导出表结构(含分区),再用mysqldump --no-create-info --single-transaction导出数据,避免结构+数据混在同一文件中导致重放失败 - 检查源表
SHOW CREATE TABLE t1输出末尾是否含PARTITION BY ...,若无,说明该表实际已退化为普通表(例如执行过ALTER TABLE t1 REMOVE PARTITIONING但未报错) - 目标库需开启
sql_mode中的NO_ENGINE_SUBSTITUTION,否则遇到源表用MyISAM分区(虽不推荐)时会静默转成InnoDB,分区信息丢失
使用 mysqlpump 迁移分区表时,--skip-definer 会导致分区 DDL 被截断?
会。mysqlpump 在 --skip-definer 模式下不仅省略 DEFINER,还会连带跳过整个 PARTITION 子句——这是其 5.7.21+ 版本的一个未文档化行为。现象是:导入后表存在、数据可写入,但 SELECT * FROM INFORMATION_SCHEMA.PARTITIONS WHERE TABLE_NAME = 't1' 返回空结果。
实操建议:
- 绝对不要对分区表使用
mysqlpump --skip-definer;如需去 definer,应在 dump 后用 sed 替换DEFINER=`user`@`host`为空,而非依赖参数 - 用
mysqlpump --include-databases=db1 --users --grants全量导出时,务必加--set-gtid-purged=OFF,否则 GTID 信息可能干扰分区表的CREATE TABLE顺序 - 若目标库 MySQL 版本低于源库(如从 8.0.33 迁到 5.7.40),
mysqlpump生成的分区语法(如COLUMNS多列分区)会直接报错,此时必须降级用mysqldump
物理拷贝 .ibd 文件迁移分区表,为什么 ALTER TABLE ... IMPORT TABLESPACE 总失败?
因为分区表的每个分区对应独立 .ibd 文件,但它们共享同一张表的 ibdata1 元数据和 INFORMATION_SCHEMA 记录。直接拷贝单个 .ibd 无法重建分区关系,IMPORT TABLESPACE 只支持非分区表或独立分区表(即建表时指定 KEY(column) PARTITION BY KEY 且未用子分区)。
实操建议:
- 物理迁移唯一可行路径是停机 + 拷贝整个
datadir下对应数据库目录,包括db1/t1#P#p0.ibd、t1#P#p1.ibd、t1.frm(5.7)或t1.sdi(8.0),以及db1/db.opt - 若仅想迁移某几个分区(如归档旧分区),应改用
ALTER TABLE t1 EXCHANGE PARTITION p0 WITH TABLE t1_archive先交换到普通表,再用mysqldump导出该普通表 - 拷贝后首次启动目标 MySQL 前,必须确保
innodb_file_per_table=ON且innodb_page_size与源库完全一致,否则.ibd文件加载失败并报Tablespace is missing for table
跨版本迁移(如 5.7 → 8.0)时,分区表达式里的函数兼容性怎么验证?
MySQL 8.0 废弃了部分用于分区的函数,例如 TO_DAYS() 在 8.0.28+ 中仍可用但标记为 deprecated,而 YEARWEEK() 的返回值类型变更会导致 5.7 的分区定义在 8.0 导入时报 ERROR 1064 (42000): You have an error in your SQL syntax。
实操建议:
- 在源库执行
SELECT PARTITION_NAME, PARTITION_EXPRESSION FROM INFORMATION_SCHEMA.PARTITIONS WHERE TABLE_SCHEMA='db1' AND TABLE_NAME='t1',提取所有分区表达式,逐条在目标库的 MySQL 8.0 客户端中运行SELECT <expression>;验证是否报错或返回类型变化 - 若表达式含
UNIX_TIMESTAMP(col),需确认col是否为DATETIME类型——8.0 要求必须是DATETIME或TIMESTAMP,DATE类型会触发隐式转换失败 - 时间分区建议统一改用
RANGE COLUMNS(如PARTITION BY RANGE COLUMNS(dt) (PARTITION p0 VALUES LESS THAN ('2023-01-01'))),它不依赖函数计算,跨版本最稳定
分区迁移真正的难点不在工具选择,而在于「分区定义是否被当作一等公民对待」——mysqldump 会导出它,mysqlpump 可能悄悄丢掉它,物理文件里它分散在多个 .ibd 中,跨版本时它又依赖函数语义一致性。任何环节少验一个 SHOW CREATE TABLE,上线后就只剩 SELECT COUNT(*) FROM INFORMATION_SCHEMA.PARTITIONS 返回 1 的沉默。


















