mysql迁移数据时如何处理大表_mysql大表迁移方案

来源:这里教程网 时间:2026-02-28 20:52:15 作者:

大表迁移时为什么不能直接用 INSERT INTO ... SELECT

因为会锁表、占满内存、拖垮主库。MySQL 在执行

INSERT INTO t2 SELECT * FROM t1
时,如果
t1
是千万级大表,事务会长时间持有 MDL 锁,阻塞所有 DDL 和部分 DML;同时 binlog 写入压力剧增,从库容易延迟数小时甚至断连。

实操建议:

禁用该方式迁移单表 >500 万行的数据 如必须用,务必在业务低峰期 + 设置
innodb_lock_wait_timeout=30
防死锁
提前在目标库关闭
autocommit
,手动分段提交(但依然不推荐)

pt-online-schema-change 能否用于纯数据迁移

可以,但它本质是「在线改表」工具,不是迁移工具。它通过创建影子表 + 触发器同步增量,适合结构变更场景;若只迁数据不改结构,反而引入额外风险:触发器可能丢失更新、主从 GTID 不一致、触发器堆积导致主库 CPU 暴涨。

实操建议:

仅当需同步迁移 + 同时修改表结构(如加索引、改字段)时才启用
pt-online-schema-change
纯数据迁移请用
mysqldump --where
分批导出,或
mydumper
并行导出
使用前确认源库
binlog_format=ROW
,否则触发器无法捕获变更

用 mydumper 导出大表要注意哪些参数

mydumper
是 C 实现的并行逻辑导出工具,比
mysqldump
快 3–5 倍,但默认行为对大表不友好:它会把整张表当一个 chunk 导出,内存占用高、失败后重跑成本大。

实操建议:

强制按主键切分:加上
--chunk-filesize=64
(单位 MB)或
--rows=100000
控制每 chunk 行数
指定导出线程数:
-t 8
(根据源库 CPU 核数设,别超 2×CPU 数)
跳过统计信息避免卡住:
--no-views --no-triggers --no-sysinfo
导出时加
--trx-consistency-only
,不开启全局一致性快照(避免 FLUSH TABLES WITH READ LOCK)

导入时如何避免主键冲突和重复写入

大表迁移常跨实例、跨版本,目标库可能已有部分数据(比如历史归档),或迁移中断后重试,此时直接

myloader
会报
Duplicate entry 'xxx' for key 'PRIMARY'

实操建议:

导入前先清空目标表(如果允许):
TRUNCATE TABLE t1
,比
DELETE FROM
快且不记 binlog
如需追加或去重,用
INSERT IGNORE
REPLACE INTO
:需提前在
myloader
的 SQL 文件里批量替换
INSERT INTO
INSERT IGNORE INTO
更稳妥的做法:导入到临时表
t1_tmp
,再用
INSERT INTO t1 SELECT ... ON DUPLICATE KEY UPDATE
合并
导入后立刻校验:
SELECT COUNT(*) FROM t1
CHECKSUM TABLE t1
(注意 CHECKSUM 在 8.0.26+ 已弃用,可用
SELECT MD5(GROUP_CONCAT(...))
替代)

大表迁移真正难的不是命令怎么写,而是中间状态不可见——没日志、没进度条、不知道卡在哪一行。哪怕用了

mydumper
,也得自己加
pv
或定时查
information_schema.PROCESSLIST
看当前正在 dump 哪个 chunk。

相关推荐