迁移时ibdata1“卡住”磁盘是因为它必须完整复制且无法跳过,承载undo日志等系统结构;若存在未清理长事务,其体积可能远超所有.ibd文件总和。

为什么迁移时 ibdata1 会突然“卡住”磁盘
不是迁移工具出了问题,而是你正在复制一个无法被压缩、也无法被跳过的共享文件。ibdata1 本身不存业务数据(或只存一部分),但它强制承载 undo 日志、数据字典、change buffer、双写缓冲等系统级结构——这些内容在迁移过程中会被完整复制,且 mysqldump 或 mydumper 都无法绕过它。更麻烦的是,如果源库长期运行且存在未清理的长事务,ibdata1 里堆积的 undo 可能远超所有 .ibd 文件总和。
迁移前必须确认的三个硬性条件
别急着跑 dump,先验证这三项,否则迁移中途可能因空间不足失败:
-
SELECT @@innodb_file_per_table;返回1—— 否则所有新表仍写入ibdata1,迁移后问题照旧 -
SHOW VARIABLES LIKE 'innodb_undo_log_truncate';是ON,且innodb_max_undo_log_size已设合理上限(如1073741824)——否则迁移前 undo 就在持续膨胀 - 源库
datadir下ibdata1大小 ≤ 目标机空闲空间 × 0.7 —— 因为迁移过程需同时保留源文件、临时 dump 文件、目标实例初始化文件
真正能缓解迁移压力的操作清单
如果你已经卡在“磁盘写满、迁移中断”,优先执行以下几项,而不是重头再来:
- 在源库执行
PURGE BINARY LOGS BEFORE NOW() - INTERVAL 7 DAY;——binlog常占空间比ibdata1还大,且 purge 是秒级操作 - 检查并 kill 卡住的长事务:
SELECT TRX_ID, TRX_STARTED, TRX_STATE FROM information_schema.INNODB_TRX ORDER BY TRX_STARTED LIMIT 5;,对超 1 小时的事务手动KILL - 临时关闭非关键日志:在源库
SET GLOBAL slow_query_log = OFF;和SET GLOBAL general_log = OFF;(记得迁移完恢复) - 改用
--skip-triggers --skip-routines --no-create-info等精简参数跑mysqldump,减少单次导出体积
跨实例迁移大表时,绕开 ibdata1 的唯一可行路径
当某张表本身数据量极大(比如 >50GB),且确认它当前还在 ibdata1 里(SELECT TABLE_SCHEMA,TABLE_NAME,DATA_LENGTH,INDEX_LENGTH FROM information_schema.TABLES WHERE ENGINE='InnoDB' ORDER BY DATA_LENGTH+INDEX_LENGTH DESC LIMIT 5;),直接 dump 它会拖垮整个迁移流程。这时应单独处理:
- 确认目标库已启用
innodb_file_per_table = ON并重启 - 在源库对该表执行
FLUSH TABLES table_name FOR EXPORT;,然后复制table_name.ibd+table_name.cfg(MySQL 5.7+)到目标库对应数据库目录 - 目标库先建同结构空表(
CREATE TABLE ... ENGINE=InnoDB;),再ALTER TABLE table_name DISCARD TABLESPACE;,复制文件过去,最后ALTER TABLE table_name IMPORT TABLESPACE; - 注意:
IMPORT TABLESPACE要求表结构完全一致、server_uuid 匹配、且不能有外键依赖——这些细节漏掉就报Tablespace is not encrypted but encryption flag is set
ibdata1 本身无法被“迁移中缩小”,它的大小反映的是源库的历史负担。真正要做的,是在目标实例上从第一行配置开始就切断这个负担链——否则换台机器,三个月后又是 50GB。











