查 table_locks_waited 需用 show global status like 'table_locks_waited' 获取累计值,须与 table_locks_immediate 计算比值(应远低于 0.01)判断锁争用,配合 show open tables 和 processlist 定位瓶颈表及阻塞线程,并确认引擎为 myisam。

查 Table_locks_waited 的实时值用 SHOW STATUS
直接运行 SHOW GLOBAL STATUS LIKE 'Table_locks_waited'; 就能拿到当前累计等待次数。这个值是自 MySQL 启动以来的总和,不是瞬时速率——所以单看一次结果意义不大,要对比两次采样差值(比如间隔 60 秒)才能判断是否正在持续发生锁争用。
常见错误是只跑一次就下结论:“Table_locks_waited 是 135,不高啊”。但若 1 分钟内从 135 涨到 280,说明每秒约有 2.5 次锁等待,已属异常。
- 必须加
GLOBAL,否则可能返回会话级状态(该变量无会话级意义,但不加容易误读) - 注意大小写:
Table_locks_waited是标准拼写,table_locks_waited在部分旧版本可能也认,但不保证兼容 - 不要和
INNODB_ROW_LOCK_WAITS混淆——后者是 InnoDB 行锁统计,对 MyISAM 完全无效
判断是否真有问题:看比值,不是看绝对值
Table_locks_waited 必须和 Table_locks_immediate 对着看。前者是“等过的次数”,后者是“秒过的次数”。健康 MyISAM 实例中,Table_locks_waited / Table_locks_immediate 应远低于 0.01(即每百次锁请求最多等 1 次)。
例如当前值:Table_locks_immediate: 1147514Table_locks_waited: 135
比值 ≈ 0.000118 → 属正常范围;但如果 Table_locks_waited 达到 5000 而 Table_locks_immediate 才 8000,比值 > 0.6,就说明绝大多数写操作都在排队。
- 比值突增比绝对值更重要——可能是某张 MyISAM 表被高频写入,或某个慢
INSERT卡住锁 - 这个比值没有固定阈值,要结合业务节奏看趋势。凌晨批量导入时短暂升高是合理的,白天交易高峰持续高则危险
- 别试图“清零”它:
FLUSH STATUS会重置,但掩盖问题,不是解决手段
定位具体哪张表在拖后腿
Table_locks_waited 告诉你“有锁争用”,但不告诉你“在哪”。得立刻查 SHOW OPEN TABLES WHERE In_use > 0; —— 这个命令列出所有当前被 MyISAM 表锁占用的表,In_use 值大于 1 表示多个线程正竞争同一张表。
配合 SELECT * FROM information_schema.PROCESSLIST WHERE STATE = 'Waiting for table level lock'; 找出等待者,再顺藤摸瓜找那个 State 是 Updating 或 Writing to net 的源头线程(它大概率正拿着锁没释放)。
-
SHOW OPEN TABLES不显示锁类型(读/写),但In_use > 0几乎总是由写操作引发(MyISAM 读不加锁,除非显式LOCK TABLES ... READ) - 如果某张表反复出现在
SHOW OPEN TABLES结果里且In_use长期 > 0,基本可锁定为瓶颈表 - 务必先确认引擎:
SHOW CREATE TABLE <code>your_table; 查ENGINE=MyISAM,避免误判 InnoDB 表
监控脚本里别漏掉连接池干扰
很多线上服务用连接池(如 HikariCP、Druid),KILL 掉一个阻塞线程后,连接可能被复用,新 SQL 立刻又卡在同一张表上——看起来 Table_locks_waited 还在涨,但 PROCESSLIST 里找不到老线程了。
这时光盯 MySQL 指标不够,得同步检查应用日志:是否有未关闭的 LOCK TABLES、批量 INSERT 是否没加事务包装、有没有漏写 UNLOCK TABLES。
- MyISAM 锁是语句级的,
INSERT执行完就释放;但显式LOCK TABLES t WRITE后,必须配对UNLOCK TABLES,否则锁一直挂着 - 连接池的
maxLifetime和keepaliveTime设置过长,会让“带锁残留”的连接存活更久,放大问题 - 真正难排查的是那种“半截死掉”的连接:客户端崩溃或网络中断,MySQL 没及时感知,锁要等
wait_timeout(默认 8 小时)才释放
真正麻烦的从来不是看到 Table_locks_waited 在涨,而是它涨得不规律、不集中——可能隔几分钟突然跳几十,然后归于平静。这种毛刺型上涨往往意味着某个定时任务或异步作业在偷偷用 MyISAM 表做中间计算,没人记得它存在。











