v$lock
和v$session
,结合dba_blockers
定位阻塞源。 ,- **MySQL**:使用SHOW ENGINE INNODB STATUS
或查询information_schema.innodb_trx
。 ,- **SQL Server**:执行sp_lock
或分析sys.dm_tran_locks
动态视图。 ,锁表可能阻塞操作,需及时排查事务或死锁问题。当数据库操作突然变慢,应用出现卡顿或报错时,“锁表”往往是罪魁祸首,理解如何查看锁表信息是数据库管理和性能调优的关键技能,本文将手把手教你如何在不同主流数据库中诊断锁表问题。
什么是锁表?为什么需要关注?
数据库锁是保证数据一致性和事务隔离的核心机制,当多个会话(连接)同时竞争同一资源(如某行、某页或整张表)时,未合理释放的锁会阻塞后续操作,导致“锁表”,后果包括:
- 应用响应延迟或超时
- 事务堆积,资源耗尽
- 严重时引发业务中断
查看锁表的通用思路
- 定位阻塞源头: 找到持有锁并阻塞其他会话的会话(Blocking Session)。
- 识别被阻塞者: 找到正在等待锁释放的会话(Waiting Session)。
- 分析锁对象: 确定被锁定的具体资源(哪张表?哪行?)。
- 查看锁类型: 了解是共享锁(读锁)还是排他锁(写锁)等。
- 获取SQL语句: 查看相关会话正在执行的SQL,定位问题代码。
主流数据库查看锁表方法详解
MySQL (InnoDB 引擎)
InnoDB提供丰富的锁信息视图:
-
查看当前所有线程状态与锁等待:
SHOW ENGINE INNODB STATUSG
在输出结果中找到
TRANSACTIONS
和LATEST DETECTED DEADLOCK
部分,重点关注:LOCK WAIT
:显示正在等待锁的事务。WAITING FOR THIS LOCK TO BE GRANTED
:显示被阻塞事务等待的锁信息(锁模式、等待锁定的索引/记录)。HOLDS THE LOCK(S)
:显示阻塞事务当前持有的锁信息。
-
查询
information_schema
系统视图 (更结构化):-- 查看当前所有锁等待关系 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; -- 查看当前所有事务和锁信息 (MySQL 5.7+ / MariaDB 10.5+) SELECT * FROM sys.innodb_lock_waits; -- 需要先安装sys库 SELECT * FROM performance_schema.data_lock_waits; -- MySQL 8.0+
-
查看当前活动进程:
SHOW FULL PROCESSLIST;
观察
State
列,出现如Waiting for table metadata lock
、Waiting for row lock
等状态表明可能被阻塞,记录Id
,可进一步分析或终止(KILL
)。
PostgreSQL
PostgreSQL 提供强大的pg_locks
和pg_stat_activity
视图。
-
查询锁等待关系:
SELECT blocked_locks.pid AS blocked_pid, blocked_activity.usename AS blocked_user, blocked_activity.query AS blocked_statement, blocking_locks.pid AS blocking_pid, blocking_activity.usename AS blocking_user, blocking_activity.query AS blocking_statement FROM pg_catalog.pg_locks blocked_locks JOIN pg_catalog.pg_stat_activity blocked_activity ON blocked_activity.pid = blocked_locks.pid JOIN pg_catalog.pg_locks blocking_locks ON blocking_locks.locktype = blocked_locks.locktype AND blocking_locks.DATABASE IS NOT DISTINCT FROM blocked_locks.DATABASE AND blocking_locks.relation IS NOT DISTINCT FROM blocked_locks.relation AND blocking_locks.page IS NOT DISTINCT FROM blocked_locks.page AND blocking_locks.tuple IS NOT DISTINCT FROM blocked_locks.tuple AND blocking_locks.virtualxid IS NOT DISTINCT FROM blocked_locks.virtualxid AND blocking_locks.transactionid IS NOT DISTINCT FROM blocked_locks.transactionid AND blocking_locks.classid IS NOT DISTINCT FROM blocked_locks.classid AND blocking_locks.objid IS NOT DISTINCT FROM blocked_locks.objid AND blocking_locks.objsubid IS NOT DISTINCT FROM blocked_locks.objsubid AND blocking_locks.pid != blocked_locks.pid JOIN pg_catalog.pg_stat_activity blocking_activity ON blocking_activity.pid = blocking_locks.pid WHERE NOT blocked_locks.GRANTED;
此查询清晰列出谁被谁阻塞,以及双方执行的SQL。
-
查看所有当前锁:
SELECT * FROM pg_catalog.pg_locks pl LEFT JOIN pg_catalog.pg_stat_activity psa ON pl.pid = psa.pid;
结合
pg_stat_activity
可看到持有锁或等待锁的会话及其SQL。
Oracle Database
Oracle 提供动态性能视图V$LOCK
和V$SESSION
。
-
查询锁阻塞关系:
SELECT s1.username AS blocking_user, s1.machine AS blocking_machine, s1.sid AS blocking_sid, s1.serial# AS blocking_serial, s2.username AS blocked_user, s2.machine AS blocked_machine, s2.sid AS blocked_sid, s2.serial# AS blocked_serial, lo.object_id, do.object_name, lo.locked_mode FROM v$lock l1 JOIN v$session s1 ON l1.sid = s1.sid AND l1.block = 1 -- Blocking sessions JOIN v$lock l2 ON l2.id1 = l1.id1 AND l2.id2 = l1.id2 AND l2.request > 0 -- Blocked sessions JOIN v$session s2 ON l2.sid = s2.sid LEFT JOIN v$locked_object lo ON lo.session_id = s1.sid LEFT JOIN dba_objects do ON do.object_id = lo.object_id WHERE l1.block = 1;
此查询显示阻塞者、被阻塞者、被锁定的对象(表)及锁模式。
-
查看所有会话的锁信息:
SELECT s.sid, s.serial#, s.username, s.status, l.type, l.lmode, l.request, l.ctime, o.object_name FROM v$session s JOIN v$lock l ON s.sid = l.sid LEFT JOIN dba_objects o ON l.id1 = o.object_id WHERE l.type != 'TM' OR (l.type = 'TM' AND o.object_name IS NOT NULL); -- 过滤常见表锁(TM)
Microsoft SQL Server
SQL Server 使用动态管理视图(DMV)。
-
查询阻塞链:
SELECT wt.blocking_session_id AS blocking_spid, DB_NAME(resource_database_id) AS database_name, wt.wait_type, wt.wait_duration_ms, ses_block.host_name AS blocking_host, ses_block.program_name AS blocking_program, ses_block.login_name AS blocking_login, txt_block.text AS blocking_sql, wt.session_id AS blocked_spid, ses_blocked.host_name AS blocked_host, ses_blocked.program_name AS blocked_program, ses_blocked.login_name AS blocked_login, txt_blocked.text AS blocked_sql FROM sys.dm_os_waiting_tasks wt JOIN sys.dm_exec_sessions ses_block ON ses_block.session_id = wt.blocking_session_id JOIN sys.dm_exec_sessions ses_blocked ON ses_blocked.session_id = wt.session_id OUTER APPLY sys.dm_exec_sql_text(sql_handle_block.sql_handle) AS txt_block -- For blocking OUTER APPLY sys.dm_exec_sql_text(sql_handle_blocked.sql_handle) AS txt_blocked -- For blocked WHERE wt.blocking_session_id IS NOT NULL AND wt.session_id > 50; -- Filter out system sessions
-
查看当前所有锁:
SELECT * FROM sys.dm_tran_locks;
MongoDB
MongoDB 锁粒度在实例级别(<=3.0)或库级别(>=3.2 WiredTiger),可通过以下命令查看:
-
查看当前操作:
db.currentOp()
在输出中查找
waitingForLock: true
的文档,表示操作正在等待锁。locks
字段显示操作持有的锁类型和模式。 -
查看锁统计信息:
db.serverStatus().locks db.serverStatus().globalLock
globalLock.currentQueue.total
显示等待锁的操作数量。
遇到锁表怎么办?
- 分析原因:
- 长事务未提交/回滚?
- 低效SQL(全表扫描、缺失索引)长时间持有锁?
- 应用逻辑缺陷(如循环中逐条提交更新)?
- 死锁?
- 临时解决:
- 谨慎操作: 在业务低峰期或确认安全后,终止阻塞源头会话 (
KILL
in MySQL/PostgreSQL,ALTER SYSTEM KILL SESSION 'sid,serial#'
in Oracle,KILL
in SQL Server)。 - 优化或停止问题查询。
- 谨慎操作: 在业务低峰期或确认安全后,终止阻塞源头会话 (
- 根本解决:
- 优化SQL: 添加合适索引,避免全表扫描,减少锁定范围和时间。
- 优化事务: 缩短事务时间,尽快提交/回滚,避免在事务中执行耗时操作(如网络调用)。
- 设计优化: 考虑使用乐观锁、读写分离、分库分表。
- 调整隔离级别: 在保证一致性的前提下,适当降低隔离级别(如
READ COMMITTED
)。 - 监控告警: 部署数据库监控工具,设置锁等待超时告警。
重要注意事项
- 生产环境谨慎KILL: 强制终止会话可能导致数据不一致或事务部分完成,务必评估影响。
- 理解锁机制: 不同数据库、不同存储引擎、不同隔离级别的锁行为差异很大。
- 利用监控工具: Prometheus + Grafana + exporter, Zabbix, 商业APM工具能提供更直观的锁监控和告警。
- 定期性能审查: 预防胜于治疗。
引用说明:
- MySQL官方文档: https://dev.mysql.com/doc/refman/8.0/en/innodb-information-schema.html
- PostgreSQL官方文档: https://www.postgresql.org/docs/current/monitoring.html
- Oracle官方文档 (V$LOCK): https://docs.oracle.com/en/database/oracle/oracle-database/19/refrn/V-LOCK.html
- SQL Server官方文档 (sys.dm_tran_locks): https://docs.microsoft.com/en-us/sql/relational-databases/system-dynamic-management-views/sys-dm-tran-locks-transact-sql
- MongoDB官方文档 (db.currentOp): https://docs.mongodb.com/manual/reference/method/db.currentOp/
(本文由资深数据库工程师根据官方文档及多年运维经验总结,旨在提供准确、实用的技术指导。)
原创文章,发布者:酷盾叔,转转请注明出处:https://www.kd.cn/ask/46777.html