MySQL数据库 DDL 阻塞问题定位 【转载】[通俗易懂]

MySQL数据库 DDL 阻塞问题定位 【转载】[通俗易懂]转载 【即拿即用:MySQL 中如何定位 DDL 被阻塞的问题?】 https://dbaplus.cn/news-11-4579-1.html 作者介绍 陈臣,甲骨文MySQL首席解决方案工程师,公

MySQL数据库 DDL 阻塞问题定位 【转载】

转载

【即拿即用:MySQL 中如何定位 DDL 被阻塞的问题?】

https://dbaplus.cn/news-11-4579-1.html

作者介绍

陈臣,甲骨文MySQL首席解决方案工程师,公众号《MySQL实战》作者,有大规模的MySQL,Redis,MongoDB,ES的管理和维护经验,擅长MySQL数据库的性能优化及日常操作的原理剖析。

1.引入

经常碰到开发、测试童鞋会问,线下开发、测试环境,执行了一个DDL,发现很久都没有执行完,是不是被阻塞了?要怎么解决?包括在群里,也经常会碰到类似问题:DDL 被阻塞了,如何找到阻塞它的 SQL ?

实际上,如何解决 DDL 被阻塞的问题,是 MySQL 中一个共性且高频的问题。

下面,就这个问题,给一个清晰明了、拿来即用的解决方案:

  • 怎么判断一个DDL是不是被阻塞了 ?

  • 当DDL被阻塞时,怎么找出阻塞它的会话 ?

2.怎么判断一个 DDL是不是被阻塞了

首先,看一个简单的Demo。

session1> create table sbtest.t1(id int primary key,name varchar(10));
Query OK, 0 rows affected (0.02 sec)
session1> insert into sbtest.t1 values(1,"a");
Query OK, 1 row affected (0.01 sec)
session1> begin;
Query OK, 0 rows affected (0.00 sec)
session1> select * from sbtest.t1;
+----+------+
| id | name |
+----+------+
|  1 | a    |
+----+------+
1 row in set (0.00 sec)
session2> alter table sbtest.t1 add c1 datetime;
阻塞中。。。
session3> show processlist;
+----+-----------------+-----------+------+---------+-------+---------------------------------+---------------------------------------+
| Id | User            | Host      | db   | Command | Time  | State                           | Info                                  |
+----+-----------------+-----------+------+---------+-------+---------------------------------+---------------------------------------+
|  5 | event_scheduler | localhost | NULL | Daemon  | 47628 | Waiting on empty queue          | NULL                                  |
| 24 | root            | localhost | NULL | Sleep   |    11 |                                 | NULL                                  |
| 25 | root            | localhost | NULL | Query   |     5 | Waiting for table metadata lock | alter table sbtest.t1 add c1 datetime |
| 26 | root            | localhost | NULL | Query   |     0 | init                            | show processlist                      |
+----+-----------------+-----------+------+---------+-------+---------------------------------+---------------------------------------+
4 rows in set (0.00 sec)

判断一个 DDL 是不是被阻塞了,很简单,就是执行 show processlist ,查看 DDL 操作对应的状态。如果显示的是 Waiting for table metadata lock ,则意味着这个 DDL 被阻塞了。DDL 一旦被阻塞了,后续针对该表的所有操作都会被阻塞,都会显示 Waiting for table metadata lock 。这也是 DDL 让人闻之色变的原因。碰到了类似场景,要么 Kill DDL 操作,要么 Kill 阻塞 DDL 的会话。Kill DDL 操作是一个治标不治本的方法,毕竟 DDL 操作总要执行。除此之外,对于 DDL 操作,需要获取元数据库锁的阶段有两个:DDL 开始之初和 DDL 结束之前。如果是后者,就意味着之前的操作都要回滚,成本相对较高。所以,碰到类似场景,我们一般都会 Kill 阻塞 DDL 的会话。

那么,怎么知道是哪些会话阻塞了 DDL 呢?下面我们看看具体的定位方法。

3.定位方法

3.1 方法一:sys.schema_table_lock_waits

sys.schema_table_lock_waits 是MySQL 5.7引入的,用来定位 DDL 被阻塞的问题。

针对上面这个Demo,我们看看sys.schema_table_lock_waits的输出。

mysql> select * from sys.schema_table_lock_waitsG
*************************** 1. row ***************************
               object_schema: sbtest
                 object_name: t1
           waiting_thread_id: 62
                 waiting_pid: 25
             waiting_account: root@localhost
           waiting_lock_type: EXCLUSIVE
       waiting_lock_duration: TRANSACTION
               waiting_query: alter table sbtest.t1 add c1 datetime
          waiting_query_secs: 17
 waiting_query_rows_affected: 0
 waiting_query_rows_examined: 0
          blocking_thread_id: 61
                blocking_pid: 24
            blocking_account: root@localhost
          blocking_lock_type: SHARED_READ
      blocking_lock_duration: TRANSACTION
     sql_kill_blocking_query: KILL QUERY 24
sql_kill_blocking_connection: KILL 24
*************************** 2. row ***************************
               object_schema: sbtest
                 object_name: t1
           waiting_thread_id: 62
                 waiting_pid: 25
             waiting_account: root@localhost
           waiting_lock_type: EXCLUSIVE
       waiting_lock_duration: TRANSACTION
               waiting_query: alter table sbtest.t1 add c1 datetime
          waiting_query_secs: 17
 waiting_query_rows_affected: 0
 waiting_query_rows_examined: 0
          blocking_thread_id: 62
                blocking_pid: 25
            blocking_account: root@localhost
          blocking_lock_type: SHARED_UPGRADABLE
      blocking_lock_duration: TRANSACTION
     sql_kill_blocking_query: KILL QUERY 25
sql_kill_blocking_connection: KILL 25
2 rows in set (0.00 sec)

只有一个 alter 操作,却产生了两条记录,而且两条记录的 Kill 对象还不一样,其中一条 Kill 的对象还是 alter 操作本身。如果对表结构不熟悉或不仔细看记录内容的话,难免会 Kill 错对象。不仅如此,在 DDL 操作被阻塞后,如果后续有 N 个查询被 DDL 操作堵塞,还会产生 N*2 条记录。在定位问题时,这 N*2 条记录完全是个噪音。这个时候,就需要我们对上述记录进行过滤了。过滤的关键是 blocking_lock_type 不等于 SHARED_UPGRADABLE。SHARED_UPGRADABLE 是一个可升级的共享元数据锁,加锁期间,允许并发查询和更新,常用在 DDL 操作的第一阶段。所以,阻塞DDL的不会是SHARED_UPGRADABLE。

故而,针对上面这个 case,我们可以通过下面这个查询来精确地定位出需要 Kill 的会话。

SELECT sql_kill_blocking_connection
FROM sys.schema_table_lock_waits
WHERE blocking_lock_type <> "SHARED_UPGRADABLE"
 AND waiting_query = "alter table sbtest.t1 add c1 datetime";

 3.2 方法二:Kill DDL 之前的会话

sys.schema_table_lock_waits 是 MySQL 5.7 才引入的。但在实际生产环境,MySQL 5.6还是占有相当多的份额。如何解决MySQL 5.6的这个痛点呢 ?细究下来,导致 DDL 被阻塞的操作,无非两类:

  • 表上有慢查询未结束。

  • 表上有事务未提交。

其中,第一类比较好定位,通过 show processlist 就能发现。而第二类仅凭 show processlist 很难定位,因为未提交事务的连接在 show processlist 中的状态同空闲连接一样,都是 Sleep 。所以,网上有 Kill 空闲连接的说法,其实也不无道理,但这样做就太简单粗暴了,难免会误杀。其实,既然是事务,在 information_schema.innodb_trx中肯定会有记录,如 session1 中的事务,在表中的记录如下,

mysql> select * from information_schema.innodb_trxG
*************************** 1. row ***************************
                    trx_id: 421568246406360
                 trx_state: RUNNING
               trx_started: 2022-01-02 08:53:50
     trx_requested_lock_id: NULL
          trx_wait_started: NULL
                trx_weight: 0
       trx_mysql_thread_id: 24
                 trx_query: NULL
       trx_operation_state: NULL
         trx_tables_in_use: 0
         trx_tables_locked: 0
          trx_lock_structs: 0
     trx_lock_memory_bytes: 1128
           trx_rows_locked: 0
         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
       trx_schedule_weight: NULL
1 row in set (0.00 sec)

其中 trx_mysql_thread_id 是线程 id ,结合 information_schema.processlist ,可进一步缩小范围。所以,我们可以通过下面这个 SQL ,定位出执行时间早于 DDL 的事务。

SELECT concat("kill ", i.trx_mysql_thread_id, ";")
FROM information_schema.innodb_trx i, (
    SELECT MAX(time) AS max_time
    FROM information_schema.processlist
    WHERE state = "Waiting for table metadata lock"
      AND (info LIKE "alter%"
      OR info LIKE "create%"
      OR info LIKE "drop%"
      OR info LIKE "truncate%"
      OR info LIKE "rename%"
  )) p
WHERE timestampdiff(second, i.trx_started, now()) > p.max_time;

可喜的是,当前正在执行的查询也会显示在information_schema.innodb_trx中。所以,上面这个 SQL 同样也适用于慢查询未结束的场景。

4.MySQL 5.7中使用sys.schema_table_lock_waits的注意事项

sys.schema_table_lock_waits 视图依赖了一张 MDL 相关的表-performance_schema.metadata_locks。该表是 MySQL 5.7 引入的,会显示 MDL 的相关信息,包括作用对象、锁的类型及锁的状态等。但在 MySQL 5.7 中,该表默认为空,因为与之相关的 instrument 默认没有开启。MySQL 8.0 才默认开启。

mysql> select * from performance_schema.setup_instruments where name="wait/lock/metadata/sql/mdl";
+----------------------------+---------+-------+
| NAME                       | ENABLED | TIMED |
+----------------------------+---------+-------+
| wait/lock/metadata/sql/mdl | NO      | NO    |
+----------------------------+---------+-------+
1 row in set (0.00 sec)

所以,在 MySQL 5.7 中,如果我们要使用 sys.schema_table_lock_waits ,必须首先开启 MDL 相关的 instrument。开启方式很简单,直接修改 performance_schema.setup_instruments 表即可。

具体SQL如下:

UPDATE performance_schema.setup_instruments SET ENABLED = "YES", TIMED = "YES"
WHERE NAME = "wait/lock/metadata/sql/mdl";

但这种方式是临时生效,实例重启后,又会恢复为默认值。建议同步修改配置文件。

[mysqld]
performance-schema-instrument="wait/lock/metadata/sql/mdl=ON"

5.总结

1)执行 show processlist ,如果 DDL 的状态是 Waiting for table metadata lock  ,则意味着这个 DDL 被阻塞了。

2)定位导致 DDL 被阻塞的会话,常用的方法有两种:

  • sys.schema_table_lock_waits

SELECT sql_kill_blocking_connection
FROM sys.schema_table_lock_waits
WHERE blocking_lock_type <> "SHARED_UPGRADABLE"
  AND (waiting_query LIKE "alter%"
  OR waiting_query LIKE "create%"
  OR waiting_query LIKE "drop%"
  OR waiting_query LIKE "truncate%"
  OR waiting_query LIKE "rename%");

这种方法适用于 MySQL 5.7 和 8.0。

注意,MySQL 5.7 中,MDL 相关的 instrument 默认没有打开。

  • Kill DDL 之前的会话
SELECT concat("kill ", i.trx_mysql_thread_id, ";")
FROM information_schema.innodb_trx i, (
    SELECT MAX(time) AS max_time
    FROM information_schema.processlist
    WHERE state = "Waiting for table metadata lock"
      AND (info LIKE "alter%"
      OR info LIKE "create%"
      OR info LIKE "drop%"
      OR info LIKE "truncate%"
      OR info LIKE "rename%"
  )) p
WHERE timestampdiff(second, i.trx_started, now()) > p.max_time;

如果 MySQL 5.7 中 MDL 相关的 instrument 没有打开或在 MySQL 5.6 中,可使用该方法。

原文地址:https://www.cnblogs.com/xuliuzai/archive/2022/06/25/16411582.html

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
转载请注明出处: https://daima100.com/5082.html

(0)
上一篇 2023-05-24
下一篇 2023-05-24

相关推荐

  • Redis学习笔记(十六) Sentinel(哨兵)(下)

    Redis学习笔记(十六) Sentinel(哨兵)(下)消失了一段时间,我又回来啦。不多说,继续把哨兵看完。 检测主观下线状态 默认情况下,Sentinel会以每秒一次的频率向所有与他创建了命令连接的实例(主从服务器以及其他Sentinel)发送PING命

    2023-03-09
    149
  • 基于iPython和Python的数据分析实践

    基于iPython和Python的数据分析实践在当今大数据时代,数据分析已成为企业决策的重要工具。iPython和Python是数据分析领域中应用较为广泛的工具,iPython是一个交互式的Python解释器,它的Notebook功能可以让用户将代码、数据以及文档结合在一起,使得数据分析更加直观,而Python由于其简洁易学以及丰富的数据分析库在数据分析领域中得到广泛应用。

    2024-06-04
    63
  • Sql Server 2008 【存储过程】 死锁 查询和杀死[通俗易懂]

    Sql Server 2008 【存储过程】 死锁 查询和杀死[通俗易懂]1 . 使用数据库中,可能出现死锁, 导致程序 无法正常使用. Create procedure [dbo].[sp_who_lock] ( @bKillPID Bit=0 — 0: 查询 1: 结

    2023-01-22
    146
  • Python Item类的用法详解

    Python Item类的用法详解在爬虫框架Scrapy中,Item是用来保存爬取数据的容器。每个Item对象是一个字典(key-value形式),可以保存从网页中获取的信息。在爬虫代码中,可以定义Item的类,在处理爬虫程序的过程中使用这个类来序列化爬取的响应并传递给Pipeline。

    2024-02-22
    118
  • innodb存储方式_innodb原理

    innodb存储方式_innodb原理前言 如果你使用过mysql数据库,对它的存储引擎:innodb,一定不会感到陌生。 众所周知,在mysql8以前,默认的存储引擎是:myslam。但mysql8之后,默认的存储引擎已经变成了:inn

    2023-04-21
    152
  • 哪个是最简单的NoSQL数据库_nosql和redis的区别

    哪个是最简单的NoSQL数据库_nosql和redis的区别在网上有关Redis相关文章满天飞的时候,这个时候我决定重温一下NoSQL。它是什么,用于解决什么问题,有哪些相类似的技术,与传统的关系型数据库有哪些差别,什么时候使用?也正如书中所说的,篇幅短小,内

    2022-12-17
    147
  • spark中的分区概念_python编程快速上手怎么样

    spark中的分区概念_python编程快速上手怎么样###@Spark分区器(Partitioner) ####HashPartitioner(默认的分区器) HashPartitioner分区原理是对于给定的key,计算其hashCode,并除以分区

    2023-05-25
    171
  • Python是面向对象的

    Python是面向对象的Python作为一门高级编程语言,具有简洁、易懂、高效、可移植和开源等优点,在各种应用场景下得到了广泛的应用。Python的面向对象编程范式为程序员提供了更为清晰灵活的设计思路和更高效的代码组织方式。在本文中,我们将从多重角度,详细探讨Python作为面向对象的编程语言的特征和优势,帮助读者更加深入理解Python面向对象编程思想的精髓。

    2024-05-13
    75

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注