MyISAM表迁移时一导就锁死业务,因mysqldump默认触发FTWRL全局读锁,所有写入立即阻塞;哪怕仅一张MyISAM表,--single-transaction即失效,备份卡在Waiting for table flush,业务INSERT/UPDATE全排队。

MyISAM表迁移时为什么一导就锁死业务
因为mysqldump默认对MyISAM表会触发FLUSH TABLES WITH READ LOCK(FTWRL),这是全局读锁,所有写入立即阻塞。哪怕只有一张MyISAM表混在InnoDB库中,--single-transaction也会失效,备份进程卡在Waiting for table flush,而业务INSERT/UPDATE全排队。
- MyISAM不支持MVCC,没法做一致性快照,只能靠FTWRL保证导出瞬间静止
- 锁持续时间 = 导出最慢那张MyISAM表的扫描耗时,大表动辄几十秒甚至分钟
- 主从延迟会同步放大:FTWRL期间binlog积压,从库追不上,
Seconds_Behind_Master飙升
mysqldump导出MyISAM表必须加--lock-all-tables吗
不是“必须”,而是“别无选择”——只要存在MyISAM表,--single-transaction自动被忽略,mysqldump内部会 fallback 到--lock-all-tables逻辑。但这个参数本身不解决根本问题,它只是把“锁一张表”升级成“锁所有表”,更伤业务。
-
--lock-all-tables本质是逐个执行FLUSH TABLES tbl_name WITH READ LOCK,锁表顺序不可控,可能加剧锁等待链 - 若同时有长事务未提交,FTWRL会一直等它释放MDL锁,备份卡住,业务线程也卡在
Waiting for table metadata lock - MySQL 8.0+ 可用
LOCK TABLES FOR BACKUP替代,它只阻塞DDL和MyISAM写入,InnoDB读写不受影响——但需确认你的MySQL版本和备份工具是否支持
不改引擎的前提下怎么降低MyISAM迁移锁影响
临时扛压可以做三件事:停写、分片、切从库。但这只是缓解,不是解法,且每一步都有硬约束。
安装、修复、更新或打包一个基于 Python 和 PyMySQL 实现的 Windows `mysql` 命令。适用于用户希望在 PowerShell/CMD 中输入 `mysql` 时重定向到 Python 实现、需要交互式输入 MySQL 连接信息、需要同步到当前用户本地 bin 目录,或需要将该能力封装成可公开复用的 Codex skill。
- 停写必须协调所有上游应用,确保无任何INSERT/UPDATE/DELETE发往该库,否则锁一释放,积压请求会瞬间冲垮连接池
- 分批导出要用
--where配合主键范围,例如--where="id BETWEEN 1 AND 100000",避免SELECT *全表扫描;但MyISAM没索引优化,WHERE条件若没走索引,照样全表扫 - 优先在从库操作:
STOP SLAVE;后再dump,导完START SLAVE;;但前提是主从延迟可控,且从库本身没被其他任务占用 - 绝不能依赖
--lock-tables=false:它跳过锁逻辑,导出数据跨时刻不一致,恢复后可能出现A表旧、B表新这种逻辑断裂
真正要做的其实是立刻启动InnoDB迁移
把ALTER TABLE t ENGINE=InnoDB当成迁移前置动作,而不是“之后再说”。现在不迁,下次备份、扩容、升级都还会踩同一颗雷。
- 迁移前务必检查
innodb_file_per_table = ON,否则所有InnoDB表会挤进系统表空间,后续无法收缩 - 迁移后第一件事不是上线,而是跑
EXPLAIN验证所有UPDATE/DELETE是否命中索引——MyISAM全表扫描不锁行,InnoDB没索引会锁全表,反而更卡 - 业务代码里所有隐式事务(比如MyISAM下UPDATE后不COMMIT也能查到)必须显式补上
COMMIT,否则连接池里的事务越积越多 - 如果原表有
FULLTEXT索引,InnoDB的分词规则和停用词不同,搜索结果会变,必须重新校验
最难的从来不是执行ALTER TABLE那条命令,而是确认所有DML语句在InnoDB下仍走索引、所有事务边界被正确标记、所有全文检索结果可接受偏差——这些细节漏掉一个,迁移后性能可能比MyISAM还差。

















