MySQL中如何定位阻塞语句
数据库中阻塞语句的查询和分析
前言
MySQL 阻塞是指在并发访问 MySQL 数据库时,某个事务占用了资源并且长时间不释放,导致其他事务无法执行或执行缓慢的情况。
MySQL 阻塞可能会导致数据库性能下降,甚至出现死锁等问题,需要马上进行处理。
在 MySQL中,线程阻塞可能是由于以下原因导致:
1、锁冲突:如果两个或者多个线程同时请求同一个资源(栗如:同一行或者同一个表),其中一个将被阻塞,直到其他线程释放锁;
2、长事务:如果一个事务占用锁的时间过长,可能会导致其它事务长时间等待甚至是超时;
3、死锁:如果两个线程或者更多的线程相互等待对方的资源,将会发生死锁(Deadlock),进而导致语句的执行阻塞。
如何排查和定位阻塞语句呢,下面来分析下?
MySQL
面对阻塞的语句如何查看呢?
首先我们来模拟2个阻塞的场景,然后使用命令来排查定位。
准备数据
CREATE TABLE `t_user` (
`id` int(11) NOT NULL,
`name` varchar(16) NOT NULL,
`age` int(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB;
insert into t_user values(1, "小明",12);
insert into t_user values(2, "小红",20);
insert into t_user values(3, "小白",19);
insert into t_user values(4, "张三",24);
insert into t_user values(5, "李四",25);
insert into t_user values(6, "王五",26);
模拟长事务的场景
事务 1
SET autocommit = 0;
begin;
UPDATE t_user SET age=12 WHERE id=1;
select SLEEP(12000);
commit;
事务 2
SET autocommit = 0;
begin;
UPDATE t_user SET age=13 WHERE id=1;
commit;
两个事务,第一个事务更新语句对 id=1
这一行加了行锁,同时这个事务 sleep 了 120 秒。事务2同样更新 id=1
这一行数据,也会加一把行锁,因为事务 1 的 sleep,导致事务 1 的行锁没有释放,事务 2 就处于阻塞中了。
下面来看下如何排查
1、使用 show processlist 查询正在运行的进程
show processlist
就是查看当前 mysql正 在执行的进程,主要有两个作用:
1、查看慢查询的sql是哪个;
2、查看出现锁的sql是哪个。
show processlist
显示的信息都是来自 MySQL 系统库 information_schema 中的 processlist 表。也可以直接查询这个。
Select * from information_schema.processlist;
$ show processlist;
+----+------+------------------+--------------------+---------+------+------------+--------------------------------------+
| Id | User | Host | db | Command | Time | State | Info |
+----+------+------------------+--------------------+---------+------+------------+--------------------------------------+
| 7 | root | 172.21.0.1:56974 | test | Query | 3 | updating | UPDATE t_user SET age=13 WHERE id=1 |
| 8 | root | 172.21.0.1:56976 | information_schema | Query | 0 | starting | show processlist |
| 9 | root | 172.21.0.1:56978 | test | Query | 2120 | User sleep | select SLEEP(12000) |
+----+------+------------------+--------------------+---------+------+------------+--------------------------------------+
来看下 show processlist
中几个参数的含义:
Id:线程的标识,如果该线程幼有问题,可以直接通过
kill <Id>
,杀死该线程;User:启动这个线程的用户;
Host: 客户端 IP 和端口号。结合
ss -n | grep :<port>
命令,可以定位到是哪个进程发送的请求;db:当前执行的命令是在哪个数据库;
Command:显示正在执行的命令,常见的有休眠(sleep),查询(query),连接(connect)等,更多的可参见官方文档Thread Command Values;
Time:表示这个状态持续的时间,单位是秒;
State:表示当前执行 sql 语句的状态,例如 executing 表示开始执行语句,
Rolling back
表示线程正在回滚事务。更多的可参见官方文档General Thread States;Info:显示的是正在执行的 sql 语句,不过这个只能显示前100个字符,要看全部的执行 sql,可使用
show full processlist
。
下面列举几个常用的查询分析栗子
按客户端 IP 分组,看哪个客户端的链接数最多
select
client_ip, count(client_ip) as client_num
from
(select
substring_index(host, ':', 1) as client_ip
from
information_schema.processlist) as connect_info
group by client_ip order by client_num desc;
+------------+------------+
| client_ip | client_num |
+------------+------------+
| 172.21.0.1 | 1 |
+------------+------------+
查询正在执行的 sql,根据时间倒叙查询,查询执行时间较长的 sql
select
*
from
information_schema.processlist
where
Command != 'Sleep'
order by Time desc;
2、使用 INNODB_TRX 查询当前运行的事务
INNODB_TRX 表提供了当前在 InnoDB 内部执行的所有事务信息,包含事务是否在等待锁,事务何时开始以及事务正在执行的 SQL 语句(如果有的话,sql语句阻塞就可以显示)。
select * from information_schema.innodb_trx where trx_state="LOCK WAIT"\G;
*************************** 1. row ***************************
trx_id: 5800
trx_state: LOCK WAIT
trx_started: 2023-07-14 01:34:06
trx_requested_lock_id: 5800:630:3:8
trx_wait_started: 2023-07-14 01:34:06
trx_weight: 2
trx_mysql_thread_id: 16
trx_query: UPDATE t_user SET age=13 WHERE id=1
trx_operation_state: starting index read
trx_tables_in_use: 1
trx_tables_locked: 1
trx_lock_structs: 2
trx_lock_memory_bytes: 1136
trx_rows_locked: 1
trx_rows_modified: 0
trx_concurrency_tickets: 0
trx_isolation_level: REPEATABLE READ
trx_unique_checks: 1
trx_foreign_key_checks: 1
trx_last_foreign_key_error: NULL
trx_adaptive_hash_latched: 0
trx_adaptive_hash_timeout: 0
trx_is_read_only: 0
trx_autocommit_non_locking: 0
看几个主要的参数,更详细的信息可参见The INFORMATION_SCHEMA INNODB_TRX Table
trx_id:InnoDB 内部的唯一事务 ID,不会为只读且非锁定事务创建 ID;
trx_state:事务的执行状态。值为 RUNNING(运行), LOCK WAIT(等待锁), ROLLING BACK(正在回滚), 和 COMMITTING(正在提交);
trx_query:事务正在执行的 sql;
trx_isolation_level:事务的隔离级别;
trx_autocommit_non_locking:无锁自动提交标识。值1表示该事务是一个 SELECT 语句,不使用
FOR UPDATE
或LOCK IN SHARED MODE
子句,并且在启用自动提交的情况下执行,因此该事务只包含这一条语句。当这一列和TRX_IS_READ_ONLY
都为 1 时,InnoDB会优化事务,以减少与更改表数据的事务相关的开销。
3、使用 INNODB_LOCKS 来查询当前出现的锁
SELECT * FROM information_schema.INNODB_LOCKS;
+--------------+-------------+-----------+-----------+-----------------+------------+------------+-----------+----------+-----------+
| lock_id | lock_trx_id | lock_mode | lock_type | lock_table | lock_index | lock_space | lock_page | lock_rec | lock_data |
+--------------+-------------+-----------+-----------+-----------------+------------+------------+-----------+----------+-----------+
| 5812:630:3:8 | 5812 | X | RECORD | `test`.`t_user` | PRIMARY | 630 | 3 | 8 | 1 |
| 5811:630:3:8 | 5811 | X | RECORD | `test`.`t_user` | PRIMARY | 630 | 3 | 8 | 1 |
+--------------+-------------+-----------+-----------+-----------------+------------+------------+-----------+----------+-----------+
来看下每个字段的含义,更详细的可参加The data_locks Table
lock_id:锁 id;
lock_trx_id:拥有锁的事务id, 可以和 INNODB_TRX 表 JOIN 得到事务的详细信息;
lock_mode:锁的模式,如下锁的类型,行级锁包括:
S、X、IS、IX
,分别代表:共享锁、排它锁、意向共享锁、意向排它锁。表级锁包括:S_GAP、X_GAP、IS_GAP、IX_GAP
和 AUTO_INC,分别代表共享间隙锁、排它间隙锁、意向共享间隙锁、意向排它间隙锁和自动递增锁;lock_type:锁的类型,RECORD 代表行级锁,TABLE 代表表级锁;
lock_table:被锁定的或者包含锁记录的表名称;
lock_index:当
LOCK_TYPE=’RECORD’
时,表示索引的名称;否则为 NULL;lock_space:当
LOCK_TYPE=’RECORD’
时,表示锁定行的表空间 ID;否则为 NULL。lock_page:当
LOCK_TYPE=’RECORD’
时,表示锁定行的页号;否则为 NULL。lock_rec:当
LOCK_TYPE=’RECORD’
时,表示一堆页面中锁定行的数量,亦即被锁定的记录号;否则为 NULL。lock_data:当
LOCK_TYPE=’RECORD’
时,表示锁定行的主键;否则为NULL。
4、使用 INNODB_LOCK_WAITS 来查询当前锁等待的关系
SELECT * FROM information_schema.INNODB_LOCK_WAITS;
+-------------------+-------------------+-----------------+------------------+
| requesting_trx_id | requested_lock_id | blocking_trx_id | blocking_lock_id |
+-------------------+-------------------+-----------------+------------------+
| 5812 | 5812:630:3:8 | 5811 | 5811:630:3:8 |
+-------------------+-------------------+-----------------+------------------+
来看下每个字段的含义,跟详细的参数可参见The data_lock_waits Table
requesting_trx_id:请求事务的 ID ;
requested_lock_id:事务所等待的锁定的 ID。可以和 INNODB_LOCKS 表 JOIN;
blocking_trx_id:阻塞事务的 ID;
blocking_lock_id:某一事务的锁的 ID,该事务阻塞了另一事务的运行。可以和 INNODB_LOCKS 表 JOIN。
总结
如果发现数据库响应变慢,排查阻塞语句,通过 show processlist 命令或者 performance_schema 表来查看当前正在执行的 SQL 语句,就能简单的分析出执行较长的 sql 语句,以及正在等待的锁和事务信息,找到阻塞的原因;
不过需要看更加详细的信息,就需要借助于下面的信息来分析定位。
1、使用 INNODB_TRX 查询当前运行的事务;
2、使用 INNODB_LOCKS 来查询当前出现的锁;
3、使用 INNODB_LOCK_WAITS 来查询当前锁等待的关系;
如果某个事务已经卡住了,可以使用 MySQL的 kill 命令来强制结束该事务,以释放资源。
当前要彻底结局问题还是要分析原因,优化查询语句或者业务中对 sql 的使用。
参考
【mysql阻塞怎么处理】https://juejin.cn/s/mysql阻塞怎么处理
【mysql线程阻塞】https://juejin.cn/s/mysql线程阻塞
【mysql: show processlist 详解】https://zhuanlan.zhihu.com/p/30743094
【mysql 使用 innodb_trx innodb_lock_waits innodb_locks 来分析锁】https://www.cnblogs.com/digdeep/p/15259091.html
【Mysql数据库系统表之详细了解INNODB_TRX、INNODB_LOCKs、INNODB_LOCK_waits、PROCESSLIST表】https://blog.csdn.net/yu121380/article/details/110132741
【MySQL 中阻塞语句的定位和分析】https://boilingfrog.github.io/2023/07/15/mysql中查询阻塞的进程/
MySQL中如何定位阻塞语句的更多相关文章
- 在mysql中如何写注释语句
//在mysql中如何写注释语句 mysql; # 这个注释直到该行结束 mysql; -- 这个注释直到该行结束 mysql ; mysql+ /* 这是一个 多行注释的形式 */ ;
- Mysql中两个select语句的连接
Mysql中两个select语句连接需要用到操作符 SQL UNION 操作符 UNION 操作符用于合并两个或多个 SELECT 语句的结果集. 请注意,UNION 内部的 SELECT 语句必须拥 ...
- MySQL 中如何定位 DDL 被阻塞的问题
经常碰到开发.测试童鞋会问,线下开发.测试环境,执行了一个DDL,发现很久都没有执行完,是不是被阻塞了?要怎么解决? 包括在群里,也经常会碰到类似问题:DDL 被阻塞了,如何找到阻塞它的 SQL ? ...
- Mysql中explain命令查看语句执行概况
Mysql中可以使用explain命令查看查询语句的执行方式,使用方法举例:explain + 查询语句 例如:explain select * from user_info 几个重要的字段说明: t ...
- MySQL中的基本SQL语句
标准SQL包含了4种基本的语句类别: DDL语句,数据定义语句,主要用来定义数据库,表名,字段,例如create,drop,alter. DML语句,数据操作语句,用来对数据记录的增删改查,还用来保证 ...
- mysql 中常用的 sql 语句
SQL分类: DDL-----数据定义语言(CREATE--创建,ALTER--修改. DROP--删除表,DECLARE--声明) DML-----数据定义语言(SELECT--查询,DELECT- ...
- MySQL中如何分析查询语句
Oracle中有explain for,mysql中也有同样的功能,那便是explain,举例如下: mysql> explain select (case (select count(*) f ...
- mysql中更新或者删除语句中子语句不能操作同一个表You can't specify target table 'test' for update in FROM clause
问题描述:有个数据表test,有个字段value,如下 mysql> select * from test;+----+------------------------------------+ ...
- 慢查询(找出mysql中超时的select语句)
第一步:进入mysql界面 //查询多少秒 才属于慢查询. show variables like ‘long_query_time’ ; 第二步: //更改这个时间值 如:select语句执行超过 ...
- MySQL中一条更新语句是如何执行的
1.创建表的语句和更新的语句 这个表的创建语句,这个表有一个主键ID和一个整型字段c: mysql> create table T(ID int primary key, c int); 如果要 ...
随机推荐
- windows系统git使用ssh方式和gitee/github进行同步
前言 在从github/gitee远程仓库获取代码时,除了使用https方式,我们还可以使用ssh连接的方式与远程仓库服务器通信,其好处是有时会比https更方便.稳定.快速. 和与普通的linux服 ...
- 小知识:使用errorstack定位特定问题
有客户遇到ORA-2289的报错,同事协助去现场排查,我帮着远程共同check下. 客户只是应用端报出的错误,为了进一步定位,服务端需要开errorstack协助定位具体问题. 下面就以这个ORA-2 ...
- 【LeetCode动态规划#14】子序列系列题(最长递增子序列、最长连续递增序列、最长重复子数组、最长公共子序列)
最长递增子序列 力扣题目链接(opens new window) 给你一个整数数组 nums ,找到其中最长严格递增子序列的长度. 子序列是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其 ...
- C# 组合键判断
e.KeyboardDevice.Modifiers 同时按下了Ctrl + H键(H要最后按,因为判断了此次事件的e.Key)修饰键只能按下Ctrl,如果还同时按下了其他修饰键,则不会进入 1 pr ...
- 深入理解 slab cache 内存分配全链路实现
本文源码部分基于内核 5.4 版本讨论 在经过上篇文章 <从内核源码看 slab 内存池的创建初始化流程> 的介绍之后,我们最终得到下面这幅 slab cache 的完整架构图: 本文笔者 ...
- Pillow模块——生成随机验证码
urls.py path('get_code/',views.get_code), views.py中 from PIL import Image,ImageFont,ImageDraw " ...
- 2023-03-02:给定一个数组arr,长度为n, 任意相邻的两个数里面至少要有一个被选出来,组成子序列,才是合法的! 求所有可能的合法子序列中,最大中位数是多少? 中位数的定义为上中位数, [1,
2023-03-02:给定一个数组arr,长度为n, 任意相邻的两个数里面至少要有一个被选出来,组成子序列,才是合法的! 求所有可能的合法子序列中,最大中位数是多少? 中位数的定义为上中位数, [1, ...
- 2022-12-07:删除重复的电子邮箱。删除重复数据后,id=3的数据被删除。请问sql语句如何写? DROP TABLE IF EXISTS `person`; CREATE TABLE `per
2022-12-07:删除重复的电子邮箱.删除重复数据后,id=3的数据被删除.请问sql语句如何写? DROP TABLE IF EXISTS `person`; CREATE TABLE `per ...
- MongoDB + SpringBoot 的基础CRUD、聚合查询
1.数据准备 1.1.springboot导包 springboot版本:2.7.10 点击查看代码 <!--mongodb的包--> <dependency> <gro ...
- flex弹性布局模式下文字超出显示省略号
都知道flex弹性布局非常好用,会随分辨率不同,宽高自适,那怎么来设置在一定范围内的文字超出隐藏,显示省略号呢?其实也不难 看如下就是使用flex布局的 其实如上效果也同样离不开如下三句,只是用法不大 ...