MySQL 元数据锁查询

news/2024/9/17 18:59:48/ 标签: mysql

为什么引入MDL锁

对于引入MDL,其主要解决了2个问题,一个是事务隔离问题,比如在可重复隔离级别下,会话A在2次查询期间,会话B对表结构做了修改,两次查询结果就会不一致,无法满足可重复读的要求;另外一个是数据复制的问题,比如会话A执行了多条更新语句期间,另外一个会话B做了表结构变更并且先提交,就会导致slave在重做时,先重做alter,再重做update时就会出现复制错误的现象。

什么是MDL

在 MySQL 5.5 版本中引入了 MDL,当对一个表做增删改查操作的时候,加 MDL 读锁;当要对表做结构变更操作的时候,加 MDL 写锁。

元数据锁是server层的锁,表级锁,每执行一条DML、DDL语句时都会申请MDL锁,DML操作需要MDL读锁,DDL操作需要MDL写锁(MDL加锁过程是系统自动控制,无法直接干预,读读共享,读写互斥,写写互斥),申请MDL锁的操作会形成一个队列,队列中写锁获取优先级高于读锁。一旦出现写锁等待,不但当前操作会被阻塞,同时还会阻塞后续该表的所有操作。

事务一旦申请到MDL锁后,直到事务执行完才会将锁释放。(这里有种特殊情况如果事务中
包含DDL操作,mysql会在DDL操作语句执行前,隐式提交commit,以保证该DDL语句操作
作为一个单独的事务存在,同时也保证元数据排他锁的释放)。

查看元数据锁

在MySQL5.7中,performance_schema库中新增了metadata_locks表,专门记录MDL的相关信息。首先要开启metadata_locks锁记录,执行如下SQL开启:(8.0默认打开)

UPDATE performance_schema.setup_consumers SET ENABLED = 'YES'
WHERE NAME ='global_instrumentation';UPDATE performance_schema.setup_instruments SET ENABLED = 'YES'
WHERE NAME ='wait/lock/metadata/sql/mdl';#配置文件中添加,重启生效
performance-schema-instrument = wait/lock/metadata/sql/mdl=ON

以8.0为例模拟MDL锁和锁冲突

mysql> select * from performance_schema.metadata_locks;
+-------------+--------------------+----------------+-------------+-----------------------+-------------+---------------+-------------+-------------------+-----------------+----------------+
| OBJECT_TYPE | OBJECT_SCHEMA      | OBJECT_NAME    | COLUMN_NAME | OBJECT_INSTANCE_BEGIN | LOCK_TYPE   | LOCK_DURATION | LOCK_STATUS | SOURCE            | OWNER_THREAD_ID | OWNER_EVENT_ID |
+-------------+--------------------+----------------+-------------+-----------------------+-------------+---------------+-------------+-------------------+-----------------+----------------+
| TABLE       | performance_schema | metadata_locks | NULL        |       139653546092288 | SHARED_READ | TRANSACTION   | GRANTED     | sql_parse.cc:5768 |             402 |              4 |
+-------------+--------------------+----------------+-------------+-----------------------+-------------+---------------+-------------+-------------------+-----------------+----------------+
1 row in set (0.00 sec)

开启一个session

mysql> begin;
Query OK, 0 rows affected (0.00 sec)mysql> select * from actor;mysql> select connection_id();
+-----------------+
| connection_id() |
+-----------------+
|             362 |
+-----------------+
1 row in set (0.00 sec)

再次查询

mysql> select * from performance_schema.metadata_locks;
+-------------+--------------------+----------------+-------------+-----------------------+-------------+---------------+-------------+-------------------+-----------------+----------------+
| OBJECT_TYPE | OBJECT_SCHEMA      | OBJECT_NAME    | COLUMN_NAME | OBJECT_INSTANCE_BEGIN | LOCK_TYPE   | LOCK_DURATION | LOCK_STATUS | SOURCE            | OWNER_THREAD_ID | OWNER_EVENT_ID |
+-------------+--------------------+----------------+-------------+-----------------------+-------------+---------------+-------------+-------------------+-----------------+----------------+
| TABLE       | sakila             | actor          | NULL        |       139653546092096 | SHARED_READ | TRANSACTION   | GRANTED     | sql_parse.cc:5768 |             402 |             39 |
| TABLE       | performance_schema | metadata_locks | NULL        |       139653682246880 | SHARED_READ | TRANSACTION   | GRANTED     | sql_parse.cc:5768 |             403 |              5 |
+-------------+--------------------+-------------

此时再次查看metadata_lock表,发现多了一条actor表的加锁记录,加锁类型为SHARED_READ,且状态是已授予(GRANTED)。

如果在session2执行select期间且事务未提交,另外一个session执行了一个DDL操作,此时就会产生互斥的metadata lock:

mysql> begin;
Query OK, 0 rows affected (0.00 sec)mysql> drop table actor;
mysql> select * from performance_schema.metadata_locks;
+-------------+--------------------+----------------+-------------+-----------------------+---------------------+---------------+-------------+-------------------+-----------------+----------------+
| OBJECT_TYPE | OBJECT_SCHEMA      | OBJECT_NAME    | COLUMN_NAME | OBJECT_INSTANCE_BEGIN | LOCK_TYPE           | LOCK_DURATION | LOCK_STATUS | SOURCE            | OWNER_THREAD_ID | OWNER_EVENT_ID |
+-------------+--------------------+----------------+-------------+-----------------------+---------------------+---------------+-------------+-------------------+-----------------+----------------+
| TABLE       | sakila             | actor          | NULL        |       139653546092096 | SHARED_READ         | TRANSACTION   | GRANTED     | sql_parse.cc:5768 |             402 |             39 |
| GLOBAL      | NULL               | NULL           | NULL        |       139653617167616 | INTENTION_EXCLUSIVE | STATEMENT     | GRANTED     | sql_base.cc:5436  |             404 |             36 |
| BACKUP LOCK | NULL               | NULL           | NULL        |       139653616499728 | INTENTION_EXCLUSIVE | TRANSACTION   | GRANTED     | sql_base.cc:5443  |             404 |             36 |
| SCHEMA      | sakila             | NULL           | NULL        |       139653615812928 | INTENTION_EXCLUSIVE | TRANSACTION   | GRANTED     | sql_base.cc:5423  |             404 |             36 |
| TABLE       | sakila             | actor          | NULL        |       139653624258944 | EXCLUSIVE           | TRANSACTION   | PENDING     | sql_parse.cc:5768 |             404 |             36 |
| TABLE       | performance_schema | metadata_locks | NULL        |       139653682246880 | SHARED_READ         | TRANSACTION   | GRANTED     | sql_parse.cc:5768 |             403 |              6 |
+-------------+--------------------+----------------+-------------+-----------------------+---------------------+---------------+-------------+-------------------+-----------------+----------------+
6 rows in set (0.00 sec)

查看metadata_locks表记录 发现actor表有MDL锁冲突( SHARED_READ 和EXCLUSIVE 互斥)

通过查看 show processlist;也看到pid为364的回话,在等到元数据锁释放Waiting for table metadata lock

mysql> show processlist;
+-----+-----------------+-----------+--------+---------+--------+---------------------------------+------------------+
| Id  | User            | Host      | db     | Command | Time   | State                           | Info             |
+-----+-----------------+-----------+--------+---------+--------+---------------------------------+------------------+
|   5 | event_scheduler | localhost | NULL   | Daemon  | 412694 | Waiting on empty queue          | NULL             |
| 362 | root            | localhost | sakila | Sleep   |    441 |                                 | NULL             |
| 363 | root            | localhost | NULL   | Query   |      0 | init                            | show processlist |
| 364 | root            | localhost | sakila | Query   |    124 | Waiting for table metadata lock | drop table actor |
+-----+-----------------+-----------+--------+---------+--------+---------------------------------+------------------+

元数据锁为什么会造成系统崩溃

举一个简单例子,session1启动一个事务,对表actor执行一个简单的查询;session2对actor加一个字段;session3来对actor做一个查询;session4来对actor做一个update,各个session串行操作。

前面提到过申请MDL锁的操作会形成一个队列,队列中写锁获取优先级高于读锁。一旦出现写锁等待,不但当前操作会被阻塞,同时还会阻塞后续该表的所有操作。

也就是由于session1的一个事务没有提交,导致session2的DDL操作被阻塞,session3和session4本身不会被session1阻塞,但由于在锁队列中,session2排队更早,它准备加的是metadata lock写锁,阻塞了session3和session4的读锁。如果students是一个执行频繁的表,show processlist会发现大量‘waiting for table metadata lock’的线程,数据库连接很快就会消耗完,导致业务系统无法正常响应。

如何监控元数据锁

metadata_locks是5.7中被引入,记录了metadata lock的相关信息,包括持有对象、类型、状态等信息。
单纯查询metadata_locks这个表无法得出具体的阻塞关系,也无法得知什么语句造成的阻塞,这里要关联另外两个表performance_schema.thread和performance_schema.events_statements_history,thread表可以将线程id和show processlist中id关联,events_statements_history表可以得到事务的历史sql,关联得到一条监控元数据锁的sql语句。

mysql> SELECT locked_schema,-> locked_table,-> locked_type,-> waiting_processlist_id,-> waiting_age,-> waiting_query,-> waiting_state,-> blocking_processlist_id,-> blocking_age,-> substring_index(sql_text,"transaction_begin;" ,-1) AS blocking_query,-> sql_kill_blocking_connection-> FROM -> ( -> SELECT -> b.OWNER_THREAD_ID AS granted_thread_id,-> a.OBJECT_SCHEMA AS locked_schema,-> a.OBJECT_NAME AS locked_table,-> "Metadata Lock" AS locked_type,-> c.PROCESSLIST_ID AS waiting_processlist_id,-> c.PROCESSLIST_TIME AS waiting_age,-> c.PROCESSLIST_INFO AS waiting_query,-> c.PROCESSLIST_STATE AS waiting_state,-> d.PROCESSLIST_ID AS blocking_processlist_id,-> d.PROCESSLIST_TIME AS blocking_age,-> d.PROCESSLIST_INFO AS blocking_query,-> concat('KILL ', d.PROCESSLIST_ID) AS sql_kill_blocking_connection-> FROM performance_schema.metadata_locks a JOIN performance_schema.metadata_locks b ON a.OBJECT_SCHEMA = b.OBJECT_SCHEMA AND a.OBJECT_NAME = b.OBJECT_NAME-> AND a.lock_status = 'PENDING'-> AND b.lock_status = 'GRANTED'-> AND a.OWNER_THREAD_ID <> b.OWNER_THREAD_ID-> AND a.lock_type = 'EXCLUSIVE'-> JOIN performance_schema.threads c ON a.OWNER_THREAD_ID = c.THREAD_ID JOIN performance_schema.threads d ON b.OWNER_THREAD_ID = d.THREAD_ID-> ) t1,-> (-> SELECT thread_id, group_concat( CASE WHEN EVENT_NAME = 'statement/sql/begin' THEN "transaction_begin" ELSE sql_text END ORDER BY event_id SEPARATOR ";" ) AS sql_text-> FROM-> performance_schema.events_statements_history-> GROUP BY thread_id-> ) t2-> WHERE t1.granted_thread_id = t2.thread_id \G
*************************** 1. row ***************************locked_schema: sakilalocked_table: actorlocked_type: Metadata Lockwaiting_processlist_id: 364waiting_age: 248waiting_query: drop table actorwaiting_state: Waiting for table metadata lockblocking_processlist_id: 362blocking_age: 565blocking_query: select * from actor
sql_kill_blocking_connection: KILL 362
1 row in set (0.00 sec)

根据显示结果,processlist_id为362的线程阻塞了364的线程,我们需要kill 362即可解锁。


http://www.ppmy.cn/news/1523695.html

相关文章

SpringBoot打包部署,打包成jar和war有所不同?

1. 我的一个springboot项目&#xff0c;用mvn install打包成jar&#xff0c;换一台有jdk的机器就直接可以用java -jar 项目名.jar的方式运行&#xff0c;没任何问题&#xff0c;为什么这里不需要tomcat也可以运行了&#xff1f; 2. 然后我打包成war放进tomcat运行&#xff0c;…

centos7 网卡配置文件

1、Centos6与Centos7网络命令对照表 2、网络配置文件解释说明 静态IP配置&#xff1a; cat /etc/sysconfig/network-scripts/ifcfg-eth0 TYPEEthernet BOOTPROTOstatic DEVICEeth0 NAMEeth0 ONBOOTyes IPADDR192.168.10.250 NETMASK255.255.255.0 GATEWAY192.168.10.1…

Redis——BigKey

1. MoreKey 当redis key的数量过多时&#xff0c;使用keys*会耗费大量时间和性能&#xff0c;因此在生产上需要禁用一些危险命令。 如何禁用命令 在 redis.conf 文件 SECURITY 板块中设置 rename-command 例如禁用keys&#xff0c;flushdb&#xff0c;flushall rename-comma…

卷积神经网络(Datawhale X 李宏毅苹果书AI夏令营)

卷积神经网络(Datawhale X 李宏毅苹果书AI夏令营) 卷积神经网络是一种非常典型的网络 架构&#xff0c;常用于图像分类等任务。 一张图像是一个三维的张量&#xff0c;其中一维代表图像的 宽&#xff0c;另外一维代表图像的高&#xff0c;还有一维代表图像的通道&#xff08;…

QtC++截图支持窗口获取

介绍 在截图工具中你会发现&#xff0c;接触到窗口后会自动圈出目标窗口,个别强大一点的还能进行元素识别可以自动圈出元素&#xff0c;那么今天简单分析一下QTc如何获取窗口并圈出当前鼠标下的窗口。 介绍1.如何获取所有窗口2.比较函数3.实现窗口判断 结尾 1.如何获取所有窗口…

springboot系列--自动配置原理

一、容器功能 一、组件添加功能 一、Configuration Configuration有两种模式&#xff0c;Full模式与Lite模式。 1、配置 类组件之间无依赖关系用Lite模式加速容器启动过程&#xff0c;减少判断 2、配置类组件之间有依赖关系&#xff0c;方法会被调用得到之前单实例组件&#…

HTML:从历史演进到未来创新的网页基石

该论文为AI生成&#xff0c;请勿运用到正式的论文上&#xff0c;以下仅供参考 一、引言 1.1 研究背景 HTML&#xff08;Hypertext Markup Language&#xff09;作为网页构建的基础语言&#xff0c;在互联网的发展历程中占据着至关重要的地位。自 1993 年诞生以来&#xff0c…

去中心化网络:Web3如何颠覆传统互联网

在互联网的演进过程中&#xff0c;从最初的静态网页到交互式的Web2.0&#xff0c;技术的进步不断推动着网络的变革。而如今&#xff0c;Web3作为互联网的下一代技术&#xff0c;正以其去中心化的特性&#xff0c;逐步颠覆传统的互联网架构。本文将深入探讨Web3如何通过去中心化…

PhotoZoom Classic 9.0.2中文版新功能介绍及PhotoZoom 9使用教程

PhotoZoom Classic 9.0.2中文版简介 PhotoZoom Classic 9.0.2中文版是一款新颖的、技术上具有革命性的对数码图片进行放大的工具。通常的工具对数码图片进行放大时&#xff0c;总会降低图片的品质&#xff0c;而这款软件使用了S-SPLINE技术(一种申请过专利的&#xff0c;拥有自…

[数据集][目标检测]西红柿成熟度检测数据集VOC+YOLO格式3241张5类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;3241 标注数量(xml文件个数)&#xff1a;3241 标注数量(txt文件个数)&#xff1a;3241 标注…

江协科技stm32————11-4 SPI通信协议

目录 SPI外设简介 SPI框图 波特率控制 SPE&#xff08;SPI使能&#xff09; 配置主从模式 四种模式的选择 发送和接收数据缓冲区状态 I2C基本结构 1. SPI模式选择 2. 时钟极性和相位&#xff08;CPOL和CPHA&#xff09; 3. 波特率设置 4. 数据帧格式 5. NSS引脚管…

高度可定制的电竞鼠标,雷柏VT1 PRO MAX体验

不管是菜鸟还是老鸟&#xff0c;游戏玩到某个阶段很容易出现瓶颈&#xff0c;在游戏的某个阶段&#xff0c;这里面制约最大的除了操作之外&#xff0c;实际上还是我们用的硬件。比如在PC游戏中&#xff0c;鼠标的影响就非常大&#xff0c;像是在游戏中如果鼠标延迟过高&#xf…

时空特征融合方向小论文创新点一次性都给你!看到就是赚到

朋友们&#xff0c;今天给大家推荐一个发小论文很不错的方向&#xff1a;时空特征融合。 时空特征融合是一种提高模型性能和准确性的关键技术&#xff0c;通过结合空间和时间维度的信息&#xff0c;它可以显著提高模型的预测精度和泛化能力&#xff0c;给我们提供更全面的数据…

Ansible Tower与AWX:构建可视化的运维自动化解决方案

Ansible Tower与AWX&#xff1a;构建可视化的运维自动化解决方案 引言 随着企业数字化转型的深入&#xff0c;运维自动化逐渐成为IT管理的重要组成部分。Ansible作为一种简单、灵活且功能强大的自动化工具&#xff0c;广泛应用于配置管理、应用部署和任务自动化中。然而&…

EvoSuite使用总结

1.安装EvoSuite插件 以IDEA为例&#xff0c;在Plugins栏搜索EvoSuite后点击install&#xff0c;安装完成后重启IDEA 2.使用EvoSuite 选中文件右键选择Run EvoSuite 生成成功可以看到如下提示&#xff1a; 注意事项&#xff1a; 生成路径&#xff1a;src/test/java 使用juni…

C语言野指针

什么是野指针 野指针&#xff08;Wild Pointer&#xff09;在C语言中指的是未初始化的指针&#xff0c;即它没有被显式地指向任何有效的内存地址。使用野指针可能会导致程序访问到非法或未知的内存区域&#xff0c;从而引发不可预测的行为和错误。 为了避免出现野指针问题&am…

【Linux 从基础到进阶】FTP/SFTP 服务器搭建与管理

FTP/SFTP 服务器搭建与管理 引言 文件传输协议(FTP)和安全文件传输协议(SFTP)是常用的文件传输工具。FTP 主要用于局域网内部或可信网络中,而 SFTP 则是基于 SSH 的加密文件传输协议,适合在不安全的网络环境中使用。本文将介绍如何在 CentOS 和 Ubuntu 上搭建和管理 FT…

Script-server: 一款开源的脚本管理工具,为你的Python脚本提供一个直观的 Web UI

在日常工作中&#xff0c;我们经常会使用各种脚本来自动化任务&#xff0c;提升效率。但传统的脚本管理方式往往伴随着一些困扰&#xff1a;复杂的命令行操作、难以理解的脚本参数、缺乏直观的反馈等等。这些问题&#xff0c;让原本应该便捷的脚本管理变得繁琐。 Script-server…

使用程序方式获取与处理MySQL表数据

8.1  执行多条语句获取 MySQL 表数据 8.1.1  MySQL 中的常量 8.1.2  MySQL 中的变量 1&#xff0e;用户变量 用户可以在表达式中使用自己定义的变量&#xff0c;这样的变量称为用户变量。 用户变量在使用前必须定义和初始化&#xff0c;如果使用没有初始化的变量&#x…

《ChatGPT:强大的人工智能聊天机器人》

在当今科技飞速发展的时代&#xff0c;人工智能技术正以惊人的速度改变着我们的生活和工作方式。其中&#xff0c;ChatGPT 作为一款强大的人工智能聊天机器人&#xff0c;引起了广泛的关注和热议。 ChatGPT 是由 OpenAI 开发的一种大型语言模型。它通过对大量文本数据的学习和训…