MySQL报错1712:主键索引损坏无法ALTER表 线上无锁修复咨询
故障处理方案(适配生产环境无长锁要求)
故障基本信息对齐
- 涉及表规模:300万行,磁盘占用11GB,原引擎为InnoDB,此前运行无异常
- 触发报错:执行新增字段的ALTER操作时返回
Error Code: 1712. Index PRIMARY is corrupted - 已验证无效操作:执行
ALTER TABLE table_name ENGINE=InnoDB;未执行成功 - 核心约束:线上生产环境,不允许执行触发长时间锁表的操作
前置零锁校验(不影响线上读写)
先执行快速无锁检查确认损坏范围,全程不会加表锁:
CHECK TABLE table_name FAST QUICK;
如果返回结果仅提示主键索引存在页损坏,不需要做全表导出恢复,优先走下面的低影响修复路径。
优先方案:原生Online DDL在线修复(元数据锁仅毫秒级,全程支持读写)
MySQL 5.6及以上版本支持InnoDB在线DDL,指定无锁参数执行即可,不会阻塞业务增删改操作,仅在最终元数据切换阶段持有毫秒级锁:
ALTER TABLE table_name FORCE, ADD COLUMN 你要新增的字段名 字段类型 [字段默认值/注释], ALGORITHM=INPLACE, LOCK=NONE;
执行说明:11GB规模的InnoDB表在普通SSD服务器上后台重建耗时约3-8分钟,期间正常业务读写完全不受影响。如果执行该语句仍然返回主键损坏报错,直接跳过该方案,用下一个无锁改表工具处理。
备选方案1:pt-online-schema-change 无锁修复(全程无长锁,业务无感知)
用在线改表工具做影子表同步修复,全程不会给原表加写锁,执行逻辑是:
- 创建和原表结构完全一致的空影子表,先在空表上修复主键索引、加上需要新增的字段
- 在原表上创建轻量触发器,把原表实时产生的增删改操作同步到影子表
- 按1000行每块的小粒度分批拷贝原表存量数据到影子表,通过IO限流、主从延迟检测控制拷贝速度,避免打满资源影响业务
- 存量数据拷贝完成、增量数据追平后,执行毫秒级表名切换,替换原表完成修复
执行参考命令(替换对应库、表、字段参数即可):
pt-online-schema-change \ --alter="ADD COLUMN 新增字段名 字段类型, DROP PRIMARY KEY, ADD PRIMARY KEY(原表主键字段名)" \ D=库名,t=表名 \ --chunk-size=1000 \ --max-lag=1 \ --lock-wait-timeout=1 \ --execute
安全提示:该工具执行过程中如果出现异常中断,会自动清理创建的触发器、影子表,不会对原表业务造成影响。
备选方案2:主从架构零影响修复
如果业务部署了主从复制架构,完全可以做到业务零感知修复:
- 先把故障实例上的读流量切到其他正常从库
- 在故障从库上完成主键修复、新增字段操作,校验数据一致性
- 把修复完成的从库提升为新主库,切写流量到新主,原故障实例下线做硬件检查——主键索引无诱因损坏大概率和磁盘坏块、内存ECC错误有关,修复后必须排查硬件问题,避免后续出现更多数据损坏。
操作禁忌
- 禁止直接执行不带
ALGORITHM=INPLACE, LOCK=NONE参数的ALTER语句,这类语句默认会加全表写锁,直接阻塞线上业务 - 尽量选择业务低峰窗口执行修复操作,即使是无锁方案也会占用一定磁盘IO,低峰执行可以把影响降到最低
- 修复完成后立刻做一次全量数据备份,避免后续出现其他页损坏问题
内容的提问来源于stack exchange,提问作者Rajesh Kumar
相关产品推荐
相关产品推荐

