慢查询触发全表扫描致索引失效时,update/delete易因优化器无法选索引而升级为表锁,表现为explain中type=all、key=null、rows≈总行数,可通过information_schema.innodb_trx等间接验证锁退化。

查慢查询是否触发全表扫描
索引缺失时,UPDATE 或 DELETE 语句容易因无法定位行而升级为表锁,本质是优化器选不到可用索引,被迫走全表扫描 + 行级锁逐行加锁,最终被 InnoDB 视为高风险操作而降级为表级锁定(尤其在 RC 隔离级别下不明显,但在 RR 下更易触发)。
- 用
EXPLAIN看执行计划:重点检查type是否为ALL、key是否为NULL、rows是否接近表总行数 - 开启慢查询日志并过滤未使用索引的语句:
log_queries_not_using_indexes = ON,但注意它会记录所有没走索引的查询(含SELECT),需结合long_query_time = 0和应用日志交叉定位写操作 - 真实场景中,常见于
WHERE条件用了函数(如WHERE DATE(create_time) = '2024-01-01')或隐式类型转换(如WHERE user_id = '123'而user_id是INT)——这两种都会让索引失效
确认行锁是否已退化为表锁
InnoDB 并不直接提供“当前某条 SQL 拿的是表锁还是行锁”的实时视图,但可通过间接方式验证是否发生了锁退化。关键不是看锁类型本身,而是看并发阻塞行为是否符合表锁特征。
- 查
information_schema.INNODB_TRX,重点关注TRX_ROWS_LOCKED和TRX_ROWS_MODIFIED:若前者远大于后者(比如锁了 50 万行,只改 1 行),大概率是扫描范围过大导致锁膨胀,已接近表锁效果 - 配合
information_schema.INNODB_LOCK_WAITS和INNODB_LOCKS(MySQL 5.7+ 已废弃,8.0+ 用performance_schema.data_locks)看等待链;若多个事务都在等同一个TABLE类型锁(如LOCK_MODE=IX+LOCK_TYPE=TABLE),说明已退化 - 最简单粗暴的方法:在测试环境对目标表执行
UPDATE ... WHERE(无索引条件),同时开另一个会话尝试ALTER TABLE—— 如果被卡住,基本可断定该 UPDATE 正持有表级意向锁且未释放
修复前先验证索引有效性
加索引不等于解决问题。很多同学加完索引发现锁问题还在,是因为索引没被用上,或者建错了字段顺序、忽略了查询模式。
- 复合索引要匹配最左前缀:比如查询是
WHERE status = ? AND create_time > ?,建(create_time, status)就无效;应建(status, create_time) - 区分等值与范围:等值字段放前面,范围字段放后面;
WHERE a = 1 AND b > 10 AND c = 2,推荐索引是(a, c, b),不是(a, b, c) - 避免冗余索引:已有
(a, b),再建(a)就浪费;可用sys.schema_redundant_indexes视图辅助识别 - 注意索引长度:对
VARCHAR(255)字段建全文索引或前缀索引时,INDEX(col(191))在 utf8mb4 下刚好够存 191 字节,但若实际数据平均长度 50,建(col(64))可能更高效且节省空间
线上加索引的锁风险控制
MySQL 5.6+ 支持 ALGORITHM=INPLACE,但不是所有情况都真正无锁。尤其是大表,即使 DDL 不阻塞 DML,也可能引发长事务堆积或复制延迟。
- 用
pt-online-schema-change或gh-ost更稳妥,它们通过影子表+触发器/ binlog 解析实现真正的非阻塞 - 如果必须用原生命令,先确认
innodb_online_alter_log_max_size足够(默认 128MB),否则 DDL 中途可能失败并回滚 - 避开业务高峰,并监控
SHOW PROCESSLIST中是否有大量Waiting for table metadata lock—— 这往往意味着有长事务正在运行,DDL 会被卡住,进而阻塞后续所有 DML - 加完索引后立刻用
EXPLAIN验证原 SQL 是否命中,别只看KEY列非空就以为万事大吉;还要看key_len是否符合预期(比如INT字段索引长度应为 4 或 5,而不是 767)
锁退化往往不是单点问题,而是索引设计、查询写法、事务粒度、隔离级别几者叠加的结果。最容易被忽略的是:你以为加了索引就安全了,但没验证执行计划是否真用了它;或者修复了 A 场景,却在 B 场景(比如新增的报表查询)里又触发了新一波全表扫描。










