首页/数据/SQL 速查/排查锁等待:谁在阻塞谁
变更与事务52 条

排查锁等待:谁在阻塞谁

线上出现锁等待时先找出持锁会话与等待链:MySQL 用 performance_schema.data_lock_waits,PostgreSQL 用 pg_locks 与 pg_blocking_pids。

SQL 速查数据更新于 2026-10-13

排查锁等待:谁在阻塞谁

线上出现锁等待时,第一步不是重启数据库,而是找出谁持有锁、谁在等谁。MySQL 8.0 用 performance_schema 的 data_locks 与 data_lock_waits 给出等待关系,配合 information_schema.INNODB_TRX 看事务状态与开始时间;PostgreSQL 用 pg_locks、pg_stat_activity 与 pg_blocking_pids() 直接拿到阻塞者 pid。定位到具体会话后,再判断是等待、取消还是终止,并从应用侧修掉根因。

基本信息

MySQL 等待关系performance_schema.data_lock_waits、data_locks(8.0 起;5.7 为 INNODB_LOCK_WAITS)
MySQL 事务视图information_schema.INNODB_TRX,含 trx_started 与 trx_rows_locked
PostgreSQLpg_locks + pg_stat_activity,pg_blocking_pids(pid) 直接返回阻塞者
排查顺序先看等待者,再顺藤摸到阻塞者,最后落到应用语句
处置原则优先取消或 kill 长事务,重启数据库是最后手段

典型使用场景

  • 线上「查询变慢」时先确认是不是锁等待,而不是急着扩容或加索引
  • 批量变更前预检:确认没有长事务占用目标表的行
  • 定位连接池里未提交的事务,找出 Sleep 却持有锁的会话
  • 排查报错 1205(MySQL 锁等待超时)与 55P03(PG 拿不到锁)
  • 死锁发生后复查残留锁与受影响事务,确认业务已恢复正常

MySQL 排查

MySQL 排查
SELECT * FROM performance_schema.data_lock_waits\G      # 等待关系:谁等谁

SELECT trx_id, trx_state, trx_started, trx_mysql_thread_id,
       trx_rows_locked, left(trx_query, 60) AS query
FROM information_schema.INNODB_TRX
ORDER BY trx_started;                    # 开始最早的往往就是阻塞源

SELECT id, user, db, command, time, state, left(info, 60)
FROM information_schema.PROCESSLIST
WHERE command <> 'Sleep'
ORDER BY time DESC;                      # 长跑语句一览

PostgreSQL 排查

PostgreSQL 排查
SELECT pid, wait_event_type, wait_event, state, query_start, left(query, 60)
FROM pg_stat_activity
WHERE wait_event_type = 'Lock';          # 所有在等锁的会话

SELECT pid, pg_blocking_pids(pid) AS blocked_by, left(query, 60)
FROM pg_stat_activity
WHERE cardinality(pg_blocking_pids(pid)) > 0;   # 每个等待者被谁挡住

SELECT pg_cancel_backend(12345);         # 温和:请求取消该会话当前语句
SELECT pg_terminate_backend(12345);      # 强制:断开整个会话

常见等待线索读法

线索含义处置方向
data_lock_waits 有记录 / blocked_by 非空确实存在锁等待关系顺着阻塞者 pid 或 thread_id 查会话
INNODB_TRX 中 trx_started 很早长事务一直未提交联系应用确认,必要时 kill
会话状态为 Sleep 却持有锁连接池里未提交的事务检查应用事务边界与连接归还逻辑
wait_event 为 Lock 但耗时极短正常的瞬时竞争观察频率,不必干预
MySQL 5.7 没有 performance_schema.data_lock_waits(8.0 才引入),老版本改用 sys.innodb_lock_waits 视图或 information_schema.INNODB_LOCK_WAITS,注意字段名与视图名都不同。
kill 之前先确认它是不是唯一的持锁者:批量 kill 会把长事务与正常事务一起清掉,引发应用大规模重试;优先用 KILL QUERY 或 pg_cancel_backend 取消语句,无效再终止会话。

易错点

  • 只看到查询慢就去扩容或加索引:真实原因是锁等待排队,先看等待视图再定位
  • 处理掉当前等待后不修根因(长事务、缺索引、连接未提交),锁问题周期性复发
  • 直接重启数据库或 kill 掉全部会话,未提交数据被回滚并引发连接风暴
  • 在 MySQL 8.0 里照搬 5.7 的 INNODB_LOCK_WAITS 查法,视图名与字段都对不上

数据来源与参考

  • MySQL 8.0 Reference Manual · Performance Schema Lock Tables
  • PostgreSQL Documentation · Monitoring Database Activity
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌