check table 仅能检测存储引擎层物理损坏,对逻辑结构损坏(如frm与字典不一致、列定义错位)无效;返回“ok”不保证无隐藏损坏,需结合监控与元数据比对预防。

用 CHECK TABLE 检测表结构损坏是否可靠
直接说结论:CHECK TABLE 能发现部分结构性问题(比如索引页损坏、记录链断裂),但对“逻辑层面的结构损坏”——例如 frm 文件与数据字典不一致、列定义错位、自增值异常跳变——它通常无能为力,甚至返回 OK。
它的本质是校验存储引擎层的物理一致性,不是校验表定义本身。InnoDB 表用它查 page corruption 有效;MyISAM 表还能顺便修复(加 REPAIR TABLE),但 InnoDB 不支持在线修复。
- 只对
MyISAM和InnoDB有效,MEMORY或CSV引擎执行会报错Storage engine 'xxx' does not support CHECK TABLE - 对分区表,必须指定具体分区名,如
CHECK TABLE t1 PARTITION (p0),否则只检查分区元数据,漏掉实际数据页 - 运行时会加读锁(InnoDB 是轻量级
LOCK TABLES FOR READ),大表可能阻塞写入,别在高峰期跑
CHECK TABLE 返回结果里哪些状态要立刻处理
执行后返回一个结果集,关键看 Msg_type 和 Msg_text 列。不是所有 Warning 都危险,但以下三类必须人工介入:
-
Msg_type = 'error':底层页校验失败,比如"Record-count mismatch"或"Index is corrupted",说明物理损坏已发生,备份+恢复是首选 -
Msg_type = 'warning'且Msg_text含"InnoDB: Record in index ... is corrupted":索引项指向非法地址,查询可能 crash 或返回脏数据 -
Msg_type = 'status'但Msg_text是"OK"—— 这个最骗人:只代表当前扫描到的页没问题,不代表没隐藏损坏(比如未分配页被误读)
示例输出中看到 msg_text: "The data file is corrupted" 就别犹豫,停写、拉备份、准备重建表。
比 CHECK TABLE 更早发现问题的替代手段
等 CHECK TABLE 报错往往已经晚了。真正有效的预防是监控 + 元数据比对:
- 定期查
information_schema.INNODB_SYS_TABLES和INNODB_SYS_COLUMNS,确认NAME、MTYPE、PRECISION是否和建表语句一致(尤其注意TINYINT(1)和BOOLEAN的隐式转换) - 开启
innodb_checksum_algorithm = crc32(MySQL 8.0+ 默认),让每次页写入都带校验,崩溃后启动时自动触发检测 - 用
mysqlcheck --check-upgrade检查版本升级后的兼容性问题,比如 MySQL 5.7 升 8.0 后utf8字符集字段可能被静默转成utf8mb3,导致插入四字节 emoji 失败
这些动作不依赖表是否可访问,甚至能在实例只读状态下做。
为什么 CHECK TABLE 有时卡住或超时
常见原因是表太大,或磁盘 I/O 延迟高,导致内部扫描线程等待 page read 超过 lock_wait_timeout(默认 31536000 秒,但实际受 innodb_lock_wait_timeout 影响)。更隐蔽的是:如果表正被 ALTER TABLE ... ALGORITHM=INPLACE 修改,CHECK TABLE 会等 DDL 锁释放,而 DDL 又在等 CHECK TABLE 的元数据锁,形成死锁。
- 加
TIMEOUT参数无效——MySQL 不支持CHECK TABLE ... WITH TIMEOUT - 安全做法是先执行
SELECT * FROM information_schema.PROCESSLIST WHERE COMMAND = 'Sleep' AND TIME > 60,杀掉长时间空闲连接,再跑CHECK TABLE - 对百 GB 级表,建议改用
innochecksum工具离线校验(需停实例),它绕过 SQL 层,直接读 .ibd 文件,速度快且不抢锁
真正难的不是命令怎么敲,而是判断“这次报 OK 是真没问题,还是刚好没扫到坏块”。得结合 binlog 位置、从库同步延迟、最近是否有异常 kill -9 或磁盘告警一起看。











