MySQL 排查全局锁

本文实验参考自《千金良方:MySQL性能优化法则金字塔》performance_schema相关章节

数据库版本:5.7.36单机

sql 复制代码
mysql> select @@version;
+------------+
| @@version  |
+------------+
| 5.7.36-log |
+------------+
1 row in set (0.00 sec)

session 1:

sql 复制代码
mysql> select connection_id();
+-----------------+
| connection_id() |
+-----------------+
|               7 |
+-----------------+
1 row in set (0.00 sec)

session 2:

sql 复制代码
mysql> select connection_id();
+-----------------+
| connection_id() |
+-----------------+
|               8 |
+-----------------+
1 row in set (0.00 sec)

session 3:

sql 复制代码
mysql> select connection_id();
+-----------------+
| connection_id() |
+-----------------+
|               9 |
+-----------------+
1 row in set (0.00 sec)

mysql> show processlist;
+----+------+-----------+-------------+---------+------+----------+------------------+
| Id | User | Host      | db          | Command | Time | State    | Info             |
+----+------+-----------+-------------+---------+------+----------+------------------+
|  7 | root | localhost | backup_test | Sleep   |   37 |          | NULL             |
|  8 | root | localhost | backup_test | Sleep   |    9 |          | NULL             |
|  9 | root | localhost | backup_test | Query   |    0 | starting | show processlist |
+----+------+-----------+-------------+---------+------+----------+------------------+
3 rows in set (0.00 sec)

session 1:开启全局读锁

sql 复制代码
mysql> flush table with read lock;
Query OK, 0 rows affected (0.00 sec)

session 2:修改任意一个表的数据

sql 复制代码
mysql> use backup_test
mysql> select * from full_backup;
+----+----------+-------+
| id | name     | class |
+----+----------+-------+
|  1 | wanger   |     9 |
|  2 | lisan    |     1 |
|  3 | zhangsan |     6 |
|  4 | si       |     2 |
|  5 | wangmazi |     4 |
+----+----------+-------+
5 rows in set (0.00 sec)
mysql> update full_backup set class=3 where id=1; //发现被阻塞

session 3:

sql 复制代码
mysql> show processlist;
+----+------+-----------+-------------+---------+------+------------------------------+-------------------------------------------+
| Id | User | Host      | db          | Command | Time | State                        | Info                                      |
+----+------+-----------+-------------+---------+------+------------------------------+-------------------------------------------+
|  7 | root | localhost | backup_test | Sleep   |  141 |                              | NULL                                      |
|  8 | root | localhost | backup_test | Query   |   49 | Waiting for global read lock | update full_backup set class=3 where id=1 |
|  9 | root | localhost | backup_test | Query   |    0 | starting                     | show processlist                          |
+----+------+-----------+-------------+---------+------+------------------------------+-------------------------------------------+
3 rows in set (0.00 sec)

发现processlist_id=8的会话在等一个全局读锁

使用常规的排查锁的表查询都为空

sql 复制代码
mysql> select * from information_schema.innodb_locks;
Empty set, 1 warning (0.00 sec)

mysql> select * from information_schema.innodb_lock_waits;
Empty set, 1 warning (0.00 sec)

mysql> select * from information_schema.innodb_trx;
Empty set (0.00 sec)

使用show engine innodb status\G;查询事务这块儿也没有什么有用的信息

sql 复制代码
------------
TRANSACTIONS
------------
Trx id counter 6939
Purge done for trx's n:o < 6939 undo n:o < 0 state: running but idle
History list length 0
LIST OF TRANSACTIONS FOR EACH SESSION:
---TRANSACTION 421678777934336, not started
0 lock struct(s), heap size 1136, 0 row lock(s)
---TRANSACTION 421678777933424, not started
0 lock struct(s), heap size 1136, 0 row lock(s)
---TRANSACTION 421678777932512, not started
0 lock struct(s), heap size 1136, 0 row lock(s)
---TRANSACTION 421678777931600, not started
0 lock struct(s), heap size 1136, 0 row lock(s)

查询performance_schema.metadata_locks表发现详情如下

sql 复制代码
mysql> select * from performance_schema.metadata_locks where owner_thread_id!=sys.ps_thread_id(connection_id())\G;
*************************** 1. row ***************************
          OBJECT_TYPE: GLOBAL	#global
        OBJECT_SCHEMA: NULL
          OBJECT_NAME: NULL
OBJECT_INSTANCE_BEGIN: 140202765115488
            LOCK_TYPE: SHARED   #共享锁
        LOCK_DURATION: EXPLICIT	#显示获取
          LOCK_STATUS: GRANTED  #已获取锁
               SOURCE:
      OWNER_THREAD_ID: 33		#thread_id=33
       OWNER_EVENT_ID: 2604
*************************** 2. row ***************************
          OBJECT_TYPE: COMMIT	#commit
        OBJECT_SCHEMA: NULL
          OBJECT_NAME: NULL
OBJECT_INSTANCE_BEGIN: 140202765018160
            LOCK_TYPE: SHARED	#共享锁
        LOCK_DURATION: EXPLICIT	#显示获取
          LOCK_STATUS: GRANTED	#已获取锁
               SOURCE:
      OWNER_THREAD_ID: 33		#thread_id=33
       OWNER_EVENT_ID: 2724
*************************** 3. row ***************************
          OBJECT_TYPE: GLOBAL	#global
        OBJECT_SCHEMA: NULL
          OBJECT_NAME: NULL
OBJECT_INSTANCE_BEGIN: 140202564139616
            LOCK_TYPE: INTENTION_EXCLUSIVE	#意向锁
        LOCK_DURATION: STATEMENT			#通过语句
          LOCK_STATUS: PENDING				#为获取到锁,等待
               SOURCE:
      OWNER_THREAD_ID: 34					#thread_id=34
       OWNER_EVENT_ID: 402
3 rows in set (0.00 sec)

通过上面的查询结果可以看到,thread_id=34的线程在等待thread_id=33的线程持有的锁。

sql 复制代码
mysql> select * from performance_schema.events_statements_current where thread_id=33\G;
*************************** 1. row ***************************
              THREAD_ID: 33
               EVENT_ID: 2598
           END_EVENT_ID: 2728
             EVENT_NAME: statement/sql/flush
                 SOURCE:
            TIMER_START: 523558101594285000
              TIMER_END: 523558104347773000
             TIMER_WAIT: 2753488000
              LOCK_TIME: 0
               SQL_TEXT: flush table with read lock
                 DIGEST: 172f9471494a101656e6cb75da3e2726
            DIGEST_TEXT: FLUSH TABLE WITH READ LOCK
         CURRENT_SCHEMA: backup_test
            OBJECT_TYPE: NULL
          OBJECT_SCHEMA: NULL
            OBJECT_NAME: NULL
  OBJECT_INSTANCE_BEGIN: NULL
            MYSQL_ERRNO: 0
      RETURNED_SQLSTATE: 00000
           MESSAGE_TEXT: NULL
                 ERRORS: 0
               WARNINGS: 0
          ROWS_AFFECTED: 0
              ROWS_SENT: 0
          ROWS_EXAMINED: 0
CREATED_TMP_DISK_TABLES: 0
     CREATED_TMP_TABLES: 0
       SELECT_FULL_JOIN: 0
 SELECT_FULL_RANGE_JOIN: 0
           SELECT_RANGE: 0
     SELECT_RANGE_CHECK: 0
            SELECT_SCAN: 0
      SORT_MERGE_PASSES: 0
             SORT_RANGE: 0
              SORT_ROWS: 0
              SORT_SCAN: 0
          NO_INDEX_USED: 0
     NO_GOOD_INDEX_USED: 0
       NESTING_EVENT_ID: NULL
     NESTING_EVENT_TYPE: NULL
    NESTING_EVENT_LEVEL: 0
1 row in set (0.00 sec)

通过如上查询,可以看到thread_id=33的线程执行的是FLUSH TABLE WITH READ LOCK锁定的,

sql 复制代码
mysql> select processlist_id,thread_id from performance_schema.threads where thread_id=33 or thread_id=34;
+----------------+-----------+
| processlist_id | thread_id |
+----------------+-----------+
|              7 |        33 |
|              8 |        34 |
+----------------+-----------+
2 rows in set (0.01 sec)

查询到线程对应的processlist_id,跟业务进行沟通是否可以进行kill等操作

kill 7;

kill掉之后,session 2的update立马执行成功

sql 复制代码
select sys.ps_thread_id(processlist_id);  --根据processlist_id查出线程号的函数
select connection_id(); --查找当前连接会话的processlist_id;
select sys.ps_thread_id(connection_id());  --查找当前连接会话的线程号

锁排查相关表
select * from information_schema.innodb_locks;
select * from information_schema.innodb_lock_waits;
select * from information_schema.innodb_trx;
相关推荐
Database_Cool_2 小时前
OLTP 和 OLAP 区别详解:分析型数据库和事务型数据库怎么选(附阿里云 AnalyticDB MySQL 选型指南)
数据库·mysql·阿里云
爱写代码的阿森2 小时前
鸿蒙三方库 | harmony-utils之KvUtil键值型数据库操作详解
数据库·华为·harmonyos·鸿蒙·huawei
Database_Cool_2 小时前
单机 MySQL 迁移到分布式数据库方便吗?阿里云 PolarDB-X 100% MySQL 协议兼容零改造平滑迁移
数据库·分布式·mysql
姜太小白3 小时前
【MySQL】 索引优化实战:解决 WHERE 等值 + IS NULL 查询,TEXT 字段报错 1167 的完整指南
数据库·mysql
窝子面4 小时前
手搓最简前后端协作-node
javascript·数据库
吳所畏惧4 小时前
宝塔面板Redis密码修改指南:SSH命令修改 vs 面板UI界面修改,哪个更靠谱?
运维·服务器·数据库·redis·缓存·ssh
DFT计算杂谈4 小时前
无 Root 权限在 Tesla K80 零门槛部署 DeepSeek 大模型
linux·服务器·网络·数据库·机器学习
HPFBoy4 小时前
log4net 数据库存日志正确配置
数据库
liuxiaowei34 小时前
【绝版教程】新版MySQL DBA高级实战进阶班 MySQL8.0 姜承尧-腾讯数据库总监
数据库·mysql·dba