图片由通义万相生成
在MySQL 8.0 中,Performance Schema 已经成为监控和分析数据库锁状态的首选方法。 在本文中,我们将探讨Performance Schema中与锁相关的表,并通过实例介绍如何使用这些表来发现当前会话的锁、识别哪些锁被阻塞、以及确定谁持有锁。
Performance Schema 中的锁相关的表
Performance Schema提供了多个与锁相关的表,主要包括:
data_locks: 当前的锁信息,包括锁的类型、模式和持有者。
data_lock_waits: 锁等待信息,展示请求锁的事务和阻塞该请求的事务之间的关系。
data_locks 表
data_locks
表提供了关于当前被数据库持有的锁的信息。这些信息包括锁的类型、模式以及所属对象等。关键列:
ENGINE: 存储引擎,对于InnoDB,值是INNODB。
ENGINE_LOCK_ID: 锁的唯一标识符。
ENGINE_TRANSACTION_ID: 事务的唯一标识符。
THREAD_ID: 执行事务的线程ID。
OBJECT_SCHEMA: 锁定对象的数据库名。
OBJECT_NAME: 锁定对象的名字。
LOCK_TYPE: 锁的类型,例如表锁或行锁。
LOCK_MODE: 锁的模式,如S(共享)或X(独:)。该值依存储引擎而定。对于InnoDB,允许的值包括 S[,GAP]、X[,GAP]、IS[,GAP]、IX[,GAP]、AUTO_INC 和 UNKNOWN。
除了 AUTO_INC 和 UNKNOWN 之外的锁模式,如果存在,则表示间隙锁。关于 S、X、IS、IX 和间隙锁的信息,请参考InnoDB锁定。
LOCK_STATUS :锁的请求状态。GRANTED持有锁 / WAITING 等待锁
LOCK_DATA: 与锁关联的数据(如果有)。锁相关的数据(如果有的话)。该值依存储引擎而定。对于InnoDB来说,
如果LOCK_TYPE 是 RECORD,则会显示一个值,否则该值为 NULL。
如果锁定在主键索引上,则会显示被锁记录的主键值。如果锁定在辅助索引上,
则会显示被锁记录的辅助索引值,并附加上主键值。如果没有主键,
LOCK_DATA 会显示选择的唯一索引的键值,或者根据InnoDB聚簇索引使用规则(参见聚簇和辅助索引),
显示InnoDB内部的唯一行ID号码。对于在supremum伪记录上获取的锁,
LOCK_DATA 会报告 "supremum伪记录"。如果包含被锁记录的页面因为在锁定期间被写到磁盘而不在缓冲池中,
InnoDB不会从磁盘获取该页面。相反,LOCK_DATA 将报告 NULL。
结合一下案例 可以认识 data_locks
相关的字段
mysql > select OBJECT_SCHEMA,OBJECT_NAME,INDEX_NAME, LOCK_MODE, LOCK_DATA from data_locks ;
+---------------+-------------+------------+-----------+------------------------+
| OBJECT_SCHEMA | OBJECT_NAME | INDEX_NAME | LOCK_MODE | LOCK_DATA |
+---------------+-------------+------------+-----------+------------------------+
| test | t | NULL | IX | NULL |
| test | t | PRIMARY | X | supremum pseudo-record |
| test | t | PRIMARY | X | 1 |
| test | t | PRIMARY | X | 4 |
| test | t | PRIMARY | X | 5 |
| test | t | PRIMARY | X | 6 |
+---------------+-------------+------------+-----------+------------------------+
6 rows in set (0.00 sec)
mysql [localhost:8030] {msandbox} (performance_schema) > select * from test.t;
+----+------+
| id | a |
+----+------+
| 1 | 3 |
| 4 | 4 |
| 5 | 6 |
| 6 | 6 |
+----+------+
4 rows in set (0.00 sec)
上述查询 中OBJECT_NAME= PRIMARY 时, LOCK_DATA 为主键的记录, 如果是 访问了非索引字段呢?select * from t where a=4 for update ;
从 MySQL 8.0.1 开始 INFORMATION_SCHEMA.INNODB_LOCKS 被P_S 的 data_locks 表取代。
注意两者的差异:
-
如果一个事务持有一个锁,只有当另一个事务正在等待这个锁时,INNODB_LOCKS 才会显示这个锁。无论是否有事务在等待这个锁,data_locks 始终会显示这个锁。
-
INNODB_LOCKS 表需要全局的 PROCESS 权限。data_locks 表则需要Performance Schema权限的只读权限,比如在要查询的表上需要 SELECT 权限。
data_lock_waits 表
data_lock_waits
表显示了锁等待情况,包含了发出锁请求的事务和阻塞该请求的事务的信息。关键列:
REQUESTING_ENGINE_LOCK_ID: 请求锁的引擎锁标识符。
REQUESTING_ENGINE_TRANSACTION_ID: 发出锁请求的事务ID。
REQUESTING_THREAD_ID: 请求锁的线程ID。
BLOCKING_ENGINE_LOCK_ID: 阻塞请求的引擎锁标识符,持有锁的锁标示符
BLOCKING_ENGINE_TRANSACTION_ID: 阻塞请求的事务ID。
BLOCKING_THREAD_ID: 持有锁的线程ID。
data_lock_waits 表和 innodb_lock_waits 表之间的差异,其实和 上面写的差异差不多。权限和字段部分有差异。
实际应用示例
以下是一些实用的SQL查询示例,帮助您利用Performance Schema监控和分析MySQL中的锁。
查找当前正在等待锁的事务
SELECT
r.THREAD_ID AS waiting_thread_id,
r.OBJECT_SCHEMA AS waiting_object_schema,
r.OBJECT_NAME AS waiting_object_name,
b.THREAD_ID AS blocking_thread_id,
b.OBJECT_SCHEMA AS blocking_object_schema,
b.OBJECT_NAME AS blocking_object_name
FROM
performance_schema.data_lock_waits w
INNER JOIN
performance_schema.data_locks b ON
b.ENGINE_LOCK_ID = w.BLOCKING_ENGINE_LOCK_ID
INNER JOIN
performance_schema.data_locks r ON
r.ENGINE_LOCK_ID = w.REQUESTING_ENGINE_LOCK_ID;
比如两个会话,比如:
session1 begin; select * from t where id=1 for update ;
session2 update t set a=4 where id=1;
查找特定会话的锁
SELECT *
FROM performance_schema.data_locks
WHERE THREAD_ID = YOUR_THREAD_ID; -- 替换为实际的线程ID
识别哪些锁被阻塞
SELECT *
FROM performance_schema.data_lock_waits;
查看谁持有锁
SELECT *
FROM performance_schema.data_locks
WHERE LOCK_STATUS = 'GRANTED';
通过 Performance Schema中的锁表,我们可以获得数据库锁的实时视图,并对锁争用事件做出快速响应,以维护数据库的稳定性和性能。
最后依然强烈安利 官方文档:
https://dev.mysql.com/doc/mysql-perfschema-excerpt/8.0/en/performance-schema-data-locks-table.html
https://dev.mysql.com/doc/mysql-perfschema-excerpt/8.0/en/performance-schema-data-lock-waits-table.html
最后的最后 1月25号 中午12点 本公众号将定时推送 2000份 红包封面,欢迎需要红包封面的朋友注意领取。