锁竞争严重时应先区分 mutex 与行锁瓶颈:查 sys.schema_mutex_waits 定位内核级热锁(如 dict_operation_lock、buf_pool_mutex),需启用 performance_schema 并开启 mutex 采集,结合 INNODB_LOCK_WAITS 交叉分析。

锁竞争严重时,别急着调参数,先确认是不是真被 mutex 或行锁卡住——这两类问题监控路径、排查逻辑和修复手段完全不同。
查 sys.schema_mutex_waits 定位内核级热锁
真正拖慢高并发写入的,往往不是 SQL 层面的行锁,而是 InnoDB 内核里几个关键 mutex 被反复争抢。比如 dict_operation_lock(字典操作锁)或 buf_pool_mutex(缓冲池锁),它们一旦成为瓶颈,SHOW ENGINE INNODB STATUS 里会看到大量 os_waits,但事务列表却看起来“没卡”。
- 必须先确保
performance_schema已启用:SELECT @@performance_schema;返回 1 才有效 - 打开 mutex 采集:
UPDATE performance_schema.setup_instruments SET ENABLED = 'YES' WHERE NAME LIKE 'wait/synch/mutex/%'; - 直接看聚合结果:
SELECT * FROM sys.schema_mutex_waits ORDER BY avg_wait_time DESC LIMIT 5;—— 这个视图比翻mutex_instances原表快得多,它已经把持有者线程、等待次数、平均等待时间都算好了 - 注意
sys库可能缺失:MySQL 5.7+ 默认带,但某些宝塔精简版或手动编译部署可能没装,得手动执行mysql -u root -p mysql 补上
用 INNODB_TRX + INNODB_LOCK_WAITS 抓行级锁阻塞链
如果响应变慢集中在某几张表、某个业务时段,大概率是事务粒度太大或没走索引导致行锁升级为间隙锁甚至表锁。这时候 sys.schema_mutex_waits 可能风平浪静,但用户请求就是卡住不动。
- 先看谁在等:
SELECT r.trx_id AS waiting_trx_id, r.trx_mysql_thread_id AS waiting_thread, r.trx_query AS waiting_query, b.trx_id AS blocking_trx_id, b.trx_mysql_thread_id AS blocking_thread, b.trx_query AS blocking_query FROM information_schema.INNODB_LOCK_WAITS w INNER JOIN information_schema.INNODB_TRX b ON b.trx_id = w.blocking_trx_id INNER JOIN information_schema.INNODB_TRX r ON r.trx_id = w.requesting_trx_id; - 重点盯
trx_state = 'LOCKWAIT'的事务,结合trx_started判断是否已挂太久;trx_rows_locked超过几百行就要警惕——可能是没走索引的范围更新 - 别只 kill 线程了事:记下
blocking_query,用EXPLAIN看执行计划,尤其检查type是不是ALL或index,key是否为NULL - 宝塔面板用户可直接在 phpMyAdmin 里执行这些语句,无需 SSH;但要注意 phpMyAdmin 默认只显示前 100 行,加
LIMIT 500避免漏掉长链
innodb_thread_concurrency 不是越大越好,设错反而加剧争抢
这个参数常被误认为“开大点就能吞更多请求”,实际它控制的是同时进入 InnoDB 内核临界区的线程数。设太高,多个线程挤在同一个 mutex 上排队;设太低,CPU 利用率上不去,还可能触发更多上下文切换开销。
- 默认值 0 表示不限制,但依赖
innodb_concurrency_tickets = 5000控制单次准入后能干多少事——这是更稳的策略,尤其对写密集场景 - 只有当
SHOW ENGINE INNODB STATUS的SEMAPHORES段里os_waits显著升高,且performance_schema.mutex_instances.COUNT_STAR > 10000时,才考虑设为 32 或 64 - MySQL 8.0.30+ 已标记为 deprecated,新环境优先调
innodb_adaptive_max_sleep_delay和线程池配置,而不是硬限并发数 - 改完必须重启 MySQL 生效,不能动态 SET;线上调参前建议先在从库验证效果
真正难处理的,是那种既不报死锁、也不显式卡住,但 QPS 上不去、延迟毛刺频发的情况——它往往藏在 mutex 等待和行锁等待的叠加态里,需要同时看 sys.schema_mutex_waits 和 INNODB_LOCK_WAITS 的交叉时间窗口,而不是单看某一个指标。


















