myisam表导致sql线程停止的典型现象是slave_sql_running为no、seconds_behind_master为null、last_sql_error含“table is read only”等关键词,根本原因是myisam不支持row格式binlog重放,必须主库执行alter table转innodb并避开锁表高峰。

MyISAM表导致SQL线程停止的典型现象
从库SHOW SLAVE STATUS\G中Slave_SQL_Running为No,Seconds_Behind_Master为NULL,Last_SQL_Error常含以下关键词:
Table is read onlyGot error 1296 from storage engineCannot execute statement: binlogging impossible since the storage engine of table ... does not support it
这不是网络或权限问题,而是MyISAM引擎本身不支持ROW格式binlog事件重放——尤其当主库binlog_format为ROW或MIXED时,从库执行DML会直接失败。即使主库设为STATEMENT,遇到NOW()、UUID()等非确定性函数也会在从库报错。
必须将MyISAM转InnoDB,不能只改从库引擎
有人想“省事”只在从库执行ALTER TABLE t ENGINE=InnoDB,这是危险操作:
- 主库仍是MyISAM,后续DML仍按MyISAM语义写入binlog,从库InnoDB无法安全重放
- 主从表结构元数据不一致,触发
ER_TABLE_NOT_LOCKED或ER_BAD_NULL_ERROR类隐式错误 - 若从库已开启
read_only=ON,该ALTER会被拒绝
正确路径只有一条:在主库执行ALTER TABLE t ENGINE=InnoDB,让binlog记录的是InnoDB建表+导入全过程,从库同步执行后自然对齐。注意:MyISAM → InnoDB不支持ALGORITHM=INPLACE,全程锁表,务必选低峰期。
大表转换前必须做的三件事
执行ALTER前漏掉任一环节,都可能引发复制延迟飙升甚至中断:
- 查表大小:
SELECT table_name, round(((data_length + index_length) / 1024 / 1024), 2) AS size_mb FROM information_schema.tables WHERE table_schema = 'db_name' AND table_name = 't';—— 超50GB建议先在从库停SQL线程后单独转换验证 - 确认主库
expire_logs_days足够长,避免转换期间binlog被自动清理,导致从库拉取失败 - 检查从库
relay_log_space_limit是否充足,否则ALTER产生的巨量relay log可能填满磁盘
别用mysqldump导出再导入替代ALTER:它会丢失自增ID起始值、触发器定义、以及binlog位点,导致主从GTID或位置严重错位。
GTID模式下跳过MyISAM相关事务是伪解法
看到Last_SQL_Error里带GTID: xxxxx:12345就执行SET GTID_NEXT='xxxxx:12345'; BEGIN; COMMIT;?这只能掩盖问题:
- MyISAM错误往往不是单条语句失败,而是状态不一致的累积结果(如索引损坏、崩溃恢复差异)
- 跳过一次后,下一条涉及同一张MyISAM表的UPDATE/DELETE大概率再次报错
- GTID跳过不修复底层引擎不兼容问题,只是把“中断点”往前挪了一步
真正要盯住的,是information_schema.tables里所有ENGINE='MyISAM'的表——只要还存在,复制风险就始终在线。清理干净之前,任何“临时恢复”都是在给故障埋雷。











