mysql卡住如何定位_MySQL 5.6中如何定位DDL被阻塞的问题

本文介绍了在MySQL 5.6中如何定位DDL被阻塞的问题,由于MySQL 5.6的特性,可以利用information_schema.innodb_trx和performance_schema.threads来查找活跃事务,并通过events_statements_history表穷举法找到可能引起阻塞的SQL,以解决此类问题。
摘要由CSDN通过智能技术生成

在上一篇文章《MySQL 5.7中如何定位DDL被阻塞的问题》中,对于DDL被阻塞问题的定位,我们主要是基于MySQL 5.7新引入的performance_schema.metadata_locks表。提出的定位方法,颇有种"锦上添花"的意味,而且,也只适用于MySQL 5.7开始的版本。

但在实际生产中,MySQL 5.6还是占绝不多数。虽然MySQL 8.0都已经GA了,但鉴于数据库的特殊性,在对待升级的这个事情上,相当一部分人还是秉持着一种“不主动”的态度。

既然MySQL 5.6用者众多,有没有一种方法,来解决MySQL 5.6的这个痛点呢?

还是之前的测试Demo

会话1开启了事务并执行了三个操作,但未提交,此时,会话2执行了alter table操作,被阻塞。

session1> begin;

Query OK,0 rows affected (0.00sec)

session1> delete from slowtech.t1 where id=2;

Query OK,1 row affected (0.00sec)

session1> select * fromslowtech.t1;+------+------+

| id | name |

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

| 1 | a |

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

row in set (0.00sec)

session1> update slowtech.t1 set name='c' where id=1;

Query OK,1 row affected (0.00sec)

Rows matched:1 Changed: 1 Warnings: 0session2> alter table slowtech.t1 add c1 int; ##被阻塞

session3>show processlist;+----+------+-----------+------+---------+------+---------------------------------+------------------------------------+

| Id | User | Host | db | Command | Time | State | Info |

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

| 2 | root | localhost | NULL | Sleep | 51 | | NULL |

| 3 | root | localhost | NULL | Query | 0 | starting | show processlist |

| 4 | root | localhost | NULL | Query | 9 | Waiting for table metadata lock | alter table slowtech.t1 add c1 int |

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

rows in set (0.00 sec)

其实,导致DDL阻塞的操作,无非两类:

1. 慢查询

2. 表上有事务未提交

其中,第一类比较好定位,通过show processlist即能发现。而第二类基本没法定位,因为未提交事务的连接在show processlist中的输出同空闲连接一样。

如下面Id为2的连接,虽然Command显示为“Sleep”,其实是事务未提交。

mysql>show processlist;+----+------+-----------+------+---------+------+---------------------------------+------------------------------------+

| Id | User | Host | db | Command | Time | State | Info |

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

| 2 | root | localhost | NULL | Sleep | 77 | | NULL |

| 3 | root | localhost | NULL | Query | 0 | starting | show processlist |

| 4 | root | localhost | NULL | Query | 44 | Waiting for table metadata lock | alter table slowtech.t1 add c1 int |

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

3 rows in set (0.00 sec)

所以,网上有kill空闲(Command为Sleep)连接的说法,其实也不无道理,但这样做就太简单粗暴了,难免会误杀。

其实,既然是事务,在information_schema. innodb_trx中肯定会有记录,如会话1中的事务,在表中的记录如下,

mysql> select * frominformation_schema.innodb_trx\G*************************** 1. row ***************************trx_id:1050390trx_state: RUNNING

trx_started:2018-07-17 08:55:32trx_requested_lock_id:NULLtrx_wait_started:NULLtrx_weight:4trx_mysql_thread_id:2trx_query:NULLtrx_operation_state:NULLtrx_tables_in_use:0trx_tables_locked:1trx_lock_structs:2trx_lock_memory_bytes:1136trx_rows_locked:3trx_rows_modified:2trx_concurrency_tickets:0trx_isolation_level:REPEATABLE READtrx_unique_checks:1trx_foreign_key_checks:1trx_last_foreign_key_error:NULLtrx_adaptive_hash_latched:0trx_adaptive_hash_timeout:0trx_is_read_only:0trx_autocommit_non_locking:0

1 row in set (0.00 sec)

其中trx_mysql_thread_id是线程id,结合performance_schema.threads,可以知道当前哪些连接上存在着活跃事务,这样就进一步缩小了可被kill的线程范围。

但从影响程度上,和kill所有Command为Sleep的连接没太大区别,毕竟,kill真正的空闲连接对业务的影响不大。

此时,依然可以借助performance_schema. events_statements_history表。

在上篇MySQL 5.7的分析中,我们是首先知道引发阻塞的线程ID,然后利用events_statements_history表,查看该线程的相关SQL。

而在MySQL 5.6中,我们并不知道引发阻塞的线程ID,但是,我们可以反其道而行之,利用穷举法,首先统计出所有线程在当前事务执行过的所有SQL,然后再判断这些SQL中是否包含目标表。

具体SQL如下,

SELECTprocesslist_id,

sql_textFROM(SELECTc.processlist_id,

substring_index( sql_text, "transaction_begin;",-1) sql_textFROMinformation_schema.innodb_trx a,

(SELECTthread_id,

group_concat(CASE WHEN EVENT_NAME = 'statement/sql/begin' THEN "transaction_begin" ELSE sql_text END ORDER BY event_id SEPARATOR ";" ) ASsql_textFROMperformance_schema.events_statements_historyGROUP BYthread_id

) b,

performance_schema.threads cWHEREa.trx_mysql_thread_id=c.processlist_idAND b.thread_id =c.thread_id

) tWHEREsql_textLIKE '%t1%';+----------------+---------------------------------------------------------------------------------------------------------+

| processlist_id | sql_text |

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

| 2 | delete from slowtech.t1 where id=2;select * from slowtech.t1;update slowtech.t1 set name='c' where id=1 |

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

1 row in set (0.01 sec)

从输出来看,确实也达到了预期效果。

需要注意的是,在MySQL5.6中,events_statements_history默认是没有开启的。

mysql> SELECT * FROM performance_schema.setup_consumers WHERE NAME LIKE '%statements%';+--------------------------------+---------+

| NAME | ENABLED |

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

| events_statements_current | YES |

| events_statements_history | NO |

| events_statements_history_long | NO |

| statements_digest | YES |

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

4 rows in set (0.00 sec)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值