在MySQL数据库中出现了阻塞问题,如何快速查找定位问题根源?在实验开始前,咱们先梳理一下有什么工具或命令查看MySQL的阻塞,另外,咱们也要一一对比其优劣,由于有些命令可能在实际环境下可能并不适用。html

1:show engine innodb statusmysql

2:Innotop工具sql

3:INNODB_TRX 等系统表数据库

下面咱们理论联系实际,经过实验来测试总结一下这个问题。首先构造测试环境,数据库测试环境为( 5.7.21 MySQL Community Server 和5.6.20-enterprise-commercial,这两个测试环境我都测试验证过)session

mysql> use MyDB;

Reading table information for completion of table and column names

You can turn off this feature to get a quicker startup with -A

Database changed

mysql> create table test_blocking(id int primary key, name varchar(12));

Query OK, 0 rows affected (0.05 sec)

mysql> insert into test_blocking

-> select 1, 'kerry' from dual;

Query OK, 1 row affected (0.00 sec)

Records: 1  Duplicates: 0  Warnings: 0

mysql> insert into test_blocking

-> select 2, 'jimmy' from dual;

Query OK, 1 row affected (0.00 sec)

Records: 1  Duplicates: 0  Warnings: 0

mysql> insert into test_blocking

-> select 3, 'kkk' from dual;

Query OK, 1 row affected (0.00 sec)

Records: 1  Duplicates: 0  Warnings: 0

准备好测试环境数据后,那么咱们接下来开始实验,为了实验效果,咱们先将参数innodb_lock_wait_timeout设置为100。mvc

mysql> show variables like 'innodb_lock_wait_timeout';

+--------------------------+-------+

| Variable_name            | Value |

+--------------------------+-------+

| innodb_lock_wait_timeout | 50    |

+--------------------------+-------+

1 row in set (0.00 sec)

mysql> set global innodb_lock_wait_timeout=100 ;

Query OK, 0 rows affected (0.00 sec)

mysql> select connection_id() from dual;

+-----------------+

| connection_id() |

+-----------------+

|               8 |

+-----------------+

1 row in set (0.00 sec)

mysql> set session autocommit=0;

Query OK, 0 rows affected (0.00 sec)

mysql> select * from test_blocking where id=1 for update;

+----+-------+

| id | name  |

+----+-------+

|  1 | kerry |

+----+-------+

1 row in set (0.00 sec)

而后在第二个链接会话中执行更新脚本,构造被阻塞的案例app

mysql> select connection_id() from dual;

+-----------------+

| connection_id() |

+-----------------+

|               9 |

+-----------------+

1 row in set (0.00 sec)

mysql> update test_blocking set name='kk' where id=1;

在第三个链接会话执行下面命令,查看TRANSACTIONS相关信息:工具

mysql> show engine innodb status\G;测试

使用show engine innodb status命令后,能够查看其输出的TRANSACTIONS部分信息,如上截图所示,找到相似TRX HAS BEEN WATING ...部分的信息,ui

经过那部分信息,咱们能够看到update test_blocking set name='kk' where id=1这个SQL语句被阻塞了14秒,一直在等待获取X Lock。

TRANSACTIONS

------------

Trx id counter 148281#下一个事务ID

Purge done for trx's n:o < 148273 undo n:o < 0 state: running but idle

History list length 552

LIST OF TRANSACTIONS FOR EACH SESSION:

---TRANSACTION 0, not started

MySQL thread id 15, OS thread handle 0x4cc64940, query id 261 localhost root cleaning up

---TRANSACTION 0, not started

MySQL thread id 14, OS thread handle 0x4cbe2940, query id 278 localhost root init

show engine innodb status

---TRANSACTION 148280, ACTIVE 24 sec

2 lock struct(s), heap size 360, 1 row lock(s)

MySQL thread id 8, OS thread handle 0x4cba1940, query id 276 localhost root cleaning up

---TRANSACTION 148279, ACTIVE 313 sec starting index read

mysql tables in use 1, locked 1

LOCK WAIT 2 lock struct(s), heap size 360, 1 row lock(s)

MySQL thread id 9, OS thread handle 0x4cc23940, query id 277 localhost root updating#线程ID为9, 操做系统线程句柄为0x4cc23940, 查询ID为277,帐号为root的UPDATE操做

update test_blocking set name='kk' where id=1#具体SQL语句

------- TRX HAS BEEN WAITING 14 SEC FOR THIS LOCK TO BE GRANTED:#TRX等待授予锁已经有14秒了

RECORD LOCKS space id 337 page no 3 n bits 72 index `PRIMARY` of table `MyDB`.`test_blocking` trx id 148279 lock_mode X locks rec but not gap waiting

#在space id=337(test_blocking表的表空间),page no=3的页上,表test_blocking上的主键索引在等待X锁

Record lock, heap no 2 PHYSICAL RECORD: n_fields 4; compact format; info bits 0

0: len 4; hex 80000001; asc;;#第一个字段是主键,制度按长为4,值为1

1: len 6; hex 000000024322; ascC";;#该字段为6个字节的事务id,这个id表示最近一次被更新的事务id(对应十进制为148258)

2: len 7; hex 9a000001f20110; asc;;#该字段为7个字节的回滚指针,用于mvcc

3: len 5; hex 6b65727279; asc kerry;;#该字段表示的是此记录的第二个字段,长度为5,值为kerry(若是表有多个字段,那么此处后面还有记录)

mysql> select * from information_schema.INNODB_SYS_DATAFILES where space=337;

+-------+--------------------------+

| SPACE | PATH                     |

+-------+--------------------------+

|   337 | ./MyDB/test_blocking.ibd |

+-------+--------------------------+

1 row in set (0.00 sec)

mysql>

可是这种方式也有一些弊端,例如生产环境很复杂,尤为是有大量事务的状况下。诸多信息根本没法清晰判断知道谁阻塞了谁;其次一点也不直观; 另外,这个也没法定位blocker 的SQL语句。这种方式只能做为辅助分析用途,经过查看取锁的详细信息,帮助进一步诊断问题。

2: Innotop工具

以下所示,Innotop工具不少状况下也不能定位到阻塞的语句(Blocking Query), 也仅仅能获取一些锁相关信息

3:经过查询information_schema数据库下与事务相关的几个系统表

仍是构造以前的测试案例,在第一个会话中使用SELECT FOR UPDATE锁定其中一行记录

mysql> use MyDB;

Database changed

mysql>  set session autocommit=0;

Query OK, 0 rows affected (0.00 sec)

mysql> select connection_id() from dual;

+-----------------+

| connection_id() |

+-----------------+

|              17 |

+-----------------+

1 row in set (0.00 sec)

mysql> select * from test_blocking where id=1 for update;

+----+-------+

| id | name  |

+----+-------+

|  1 | kerry |

+----+-------+

1 row in set (0.00 sec)

mysql>

而后在第二个链接会话中执行更新脚本,构造被阻塞的案例

mysql> use MyDB;

Database changed

mysql> select connection_id() from dual;

+-----------------+

| connection_id() |

+-----------------+

|              19 |

+-----------------+

1 row in set (0.00 sec)

mysql> update test_blocking set name='kk' where id=1;

此时阻咱们在第三个链接会话查找谁被阻塞了

SELECT b.trx_mysql_thread_id             AS 'blocked_thread_id'

,b.trx_query                      AS 'blocked_sql_text'

,c.trx_mysql_thread_id             AS 'blocker_thread_id'

,c.trx_query                       AS 'blocker_sql_text'

,( Unix_timestamp() - Unix_timestamp(c.trx_started) )

AS 'blocked_time'

FROM   information_schema.innodb_lock_waits a

INNER JOIN information_schema.innodb_trx b

ON a.requesting_trx_id = b.trx_id

INNER JOIN information_schema.innodb_trx c

ON a.blocking_trx_id = c.trx_id

WHERE  ( Unix_timestamp() - Unix_timestamp(c.trx_started) ) > 4;

SELECT a.sql_text,

c.id,

d.trx_started

FROM   performance_schema.events_statements_current a

join performance_schema.threads b

ON a.thread_id = b.thread_id

join information_schema.processlist c

ON b.processlist_id = c.id

join information_schema.innodb_trx d

ON c.id = d.trx_mysql_thread_id

where c.id=17

ORDER  BY d.trx_started\G;

以下截图所示,第一个SQL语句可以查到线程19 被线程 17阻塞了, 被阻塞的SQL语句为“update test_blocking set name='kk' where id=1;”, 可以查到被阻塞了多长时间,可是没法查到源头SQL语句。此时就须要第二个SQL语句登场,找到源头语句。

可是不要太天真的认为第二个SQL语句可以获取全部场景下的阻塞源头SQL语句,实际业务场景,会话可能在执行一个存储过程或复杂的业务,有可能它执行完阻塞源头SQL后,继续在执行其它SQL语句,此时,你抓取的是这个链接会话最后执行的SQL语句,以下所示,我简单构造了一个例子。就能构造这样的一个场景。这个我曾经写过一篇博客,分析SQL Server和ORACLE 定位查找阻塞源头SQL语句,如今看来真是大道同源,异曲同工。

mysql> select * from test_blocking where id=1 for update;

+----+-------+

| id | name  |

+----+-------+

|  1 | kerry |

+----+-------+

1 row in set (0.00 sec)

mysql> delete from student where stu_id=1001;

Query OK, 1 row affected (0.00 sec)

mysql>

总结: 最简单、方便的仍是上面两个SQL查询定位blocker的SQL语句,可是须要注意:有时候它也查不到真正阻塞的源头SQL语句。因此还需结合应用程序代码与上下文环境进行总体分析、判断!

mysql阻塞 事务_MySQL Innodb如何找出阻塞事务源头SQL相关推荐

  1. mysql dml回滚_mysql binlog回滚/闪回,前滚, 分析各表DML情况, 找出长事务与大事务...

    简介 binlog_inspector通过解释mysql/mariadb binlog/relaylog实现以下三大功能: 1)flashback/闪回/回滚, 实现DML的回滚到任意时间或者位置. ...

  2. activiti如何最后一次提交事务_MySQL如何找出未提交事务的SQL浅析

    很久之前曾经总结过一篇博客"MySQL如何找出未提交事务信息",现在看来,这篇文章中不少知识点或观点都略显肤浅,或者说不够深入,甚至说部分结论是错误的.下面重新探讨一下这个话题.那 ...

  3. mysql未提交事务sql_MySQL如何找出未提交事务的SQL浅析

    --准备测试环境数据(实验环境为MySQL 8.0.18社区版)mysql> create table kkk(id int , name varchar(12));Query OK, 0 ro ...

  4. mysql innodb禁用事务_MySQL InnoDB事务中锁问题(三)

    试想,事务如果都是串行的,那么就不需要锁了,但是性能肯定没法接受.加锁只是为了提高事务并行度,并且解决并发事务执行过程中引起的脏写.脏读.不可重复读.幻读这些问题的一种解决方案(MVCC算是一种解决脏 ...

  5. mysql innodb 事务_Mysql InnoDB事务

    事务特点 ACID ATOMICITY:原子性 一个事务必须被视为一个不可分割的最小工作单元,整个事务中的所有操作要么全部提交成功,要么全部失败回滚,对于一个事务来说,不可能只执行其中的一部分操作,这 ...

  6. mysql 表死锁_MySQL Innodb表导致死锁日志情况分析与归纳

    案例描述在定时脚本运行过程中,发现当备份表格的sql语句与删除该表部分数据的sql语句同时运行时,mysql会检测出死锁,并打印出日志. 两个sql语句如下:(1)insert into backup ...

  7. mysql 强制使用索引_快速找出MySQL数据库冗余索引和未使用索引

    冗余索引和未使用索引的危害 随着上线的业务越来越多,在MySQL数据库中建的表也会越来越多,为提高查询访问速度,会创建相应的索引.但是由于技术人员的水平参差不齐,业务下线,代码逻辑变更等原因,导致线上 ...

  8. mysql 释放空间_Mysql InnoDB删除数据后释放磁盘空间的步骤详解

    Mysql InnoDB删除数据后释放磁盘空间的方法 Innodb数据库对于已经删除的数据只是标记为删除,并不真正释放所占用的磁盘空间,这就导致InnoDB数据库文件不断增长. 如果在创建数据库的时候 ...

  9. jdbctemplate 开启事务_浅入浅出 Spring 事务传播实现原理

    本文和大家一起刨析 Spring 事务的相关源码,篇幅较长,代码片段较多,建议使用电脑阅读 本文目标 理解Spring事务管理核心接口 理解Spring事务管理的核心逻辑 理解事务的传播类型及其实现原 ...

最新文章

  1. http账户密码的截取
  2. [JDBC技术]3.JDBC数据库连接池实例
  3. 双目三维重建_【光电视界】简单介绍双目视觉三维重构
  4. 政府大数据治理的挑战及对策
  5. Java 算法 降价机器人
  6. 【LeetCode】【HOT】20. 有效的括号(栈)
  7. python 内存管理
  8. 开发中所使用的渠道(统计分析、分享、第三方登录、短信等)
  9. Atitit.attilax重要案例 项目与解决方案与成果 v6 qa15
  10. 全国道路运输管理人员考试多选练习题库
  11. 怎样修改MTK Scatter 文件
  12. 《跟任何人都聊得来》读书笔记
  13. 张家界四日自助游攻略及心得
  14. mysql linux .frm位置_linux 使用mysqlfrm
  15. uni-app 结合云函数开发小程序博客(二):云函数实现登录注册
  16. 幻方萤火 | 高速读写文件系统 3FS
  17. linux忘记root密码怎么办——重置root密码的四种方法
  18. FCN(全卷积神经网络)
  19. 【转】对 HTTP 304 的理解
  20. 中职计算机老师的一天,信息技术教师的一天

热门文章

  1. Java 为图形填充渐变色
  2. C++ STL map和multimap的简单使用
  3. C++的STL标准库学习(vector)
  4. [Python+sklearn] 拆分数据集为训练和测试子集 sklearn.model_selection.train_test_split()
  5. python应用系列教程——python使用smtp协议发送邮件:html文本邮件、图片邮件、文件附件邮件
  6. windows安装pip包
  7. 使用WSDL工具生成C#使用的WebService声明文件
  8. 基于vue-cli 将webpack3 升级到 webpack4 配置
  9. mysql增加自定义函数功能
  10. Python 批量重命名文件