当前位置: 首页 > news >正文

mysql创建索引导致死锁,数据库崩溃,完美解决方案

文章目录

  • 写在前面
  • 一、短事务场景下,执行DDL语句场景分析
    • 1、短事务场景下,执行表字段添加操作
    • 2、短事务场景下,执行表字段修改操作
    • 3、短事务场景下,执行表字段删除操作
      • (1)往里添加一条数据试试
    • 4、短事务场景下,添加索引操作
    • 5、总结
  • 二、完美解决方案
  • 三、原因分析
  • 写在后面

写在前面

DDL语句,就是对数据库对象(数据库、表、列、索引等)进行创建、删除、修改等。

之前分享过一篇mysql创建索引导致死锁,数据库崩溃,mysql的表级锁之【元数据锁(meta data lock,MDL)】全解

通过上一篇文章我们了解到,MySQL有一种表锁叫做元数据锁(meta data lock,MDL)元数据锁,执行DDL时会检查元数据锁并尝试获取。

之前一直以为,只要保证MySQL数据库当前没有长事务,就可以安枕无忧地执行DDL语句,我们天真的认为短事务场景中,DDL语句总是会在上一个事务结束后,获取到元数据锁,并不会有死锁的危险。

但是最近发现!事情并没有想象中的那么简单!就算是没有长事务,MySQL8.0在创建索引的时候,仍然有可能会导致死锁的发生!
我们一起来分析一下。

注!本文操作都是基于mysql 8.0.21InnoDB引擎,可重复读事务隔离级别下来完成的。

一、短事务场景下,执行DDL语句场景分析

先创建一个表:

CREATE TABLE `lock_test` (`id` int NOT NULL,`name` varchar(20) DEFAULT NULL,`age` int DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB;

1、短事务场景下,执行表字段添加操作

在这里插入图片描述
我们发现,当事务A尚未提交时,事务B、事务C都会处于等待状态。

当事务A一经发起commit命令,事务B紧跟着会进行执行,并执行成功,事务C在事务B之后也会执行成功。

整个过程只有正常的事务等待,并不会发生死锁。

2、短事务场景下,执行表字段修改操作

在这里插入图片描述
我们发现,修改字段的场景下和添加字段场景下的结果是一样的。

3、短事务场景下,执行表字段删除操作

在这里插入图片描述
当该表无数据时,我们会发现,当事务A执行提交之后,事务B和事务C进入死锁,此时该表的任何SQL语句都无法执行!

此时导致数据库表死锁,数据库SQL堆积越来越多,导致数据库崩溃!

(1)往里添加一条数据试试

INSERT INTO `ourea`.`lock_test`(`id`, `name`, `age`, `column_name`) VALUES (1, '1', 1, '1');

在这里插入图片描述
有数据的情况和没有数据的情况,是不一样的!

有数据时,当事务A提交之后,事务C会执行成功,当事务C提交之后,事务B才是最终执行成功。

4、短事务场景下,添加索引操作

还是保持数据库中有数据。

INSERT INTO `ourea`.`lock_test`(`id`, `name`, `age`, `column_name`) VALUES (1, '1', 1, '1');

在这里插入图片描述
我们发现,当事务A执行提交之后,事务B和事务C进入死锁,此时该表的任何SQL语句都无法执行!

此时导致数据库表死锁,数据库SQL堆积越来越多,导致数据库崩溃!

5、总结

用事实说话。

通过实例,我们可以看出,即使没有长事务,执行DDL语句仍会导致表死锁。
尤其是对索引的操作,非常危险!

二、完美解决方案

在执行DDL语句之前,通过以下SQL,首先要确保没有长事务:

SELECT * FROM information_schema.INNODB_TRX;

然后,再执行DDL语句之前,先将整表锁住,然后执行DDL语句:
在这里插入图片描述
使用如下操作,完美解决死锁问题!

-- 锁整表,加上写锁
lock table lock_test write;
-- 添加索引
CREATE INDEX index_tb ON lock_test(column_name);
-- 解锁
unlock table;

三、原因分析

当对非主键字段更改索引时,其实并不是一个原子操作,会先更新非主键字段索引,然后再更新主键索引。

当我们把主键删掉之后:

在这里插入图片描述
这种情况,和当表中有数据,执行表字段删除操作的场景一模一样。

原因是MySQL5.6引入的OnLine-DDL,一个DDL语句其实包含着两个等待操作:

  • prepare阶段:尝试获取MDL排他锁,禁止其他线程读写;
  • ddl执行阶段:降级成MDL共享锁,允许其他线程读取;
  • commit阶段:升级成MDL排他锁,禁止其他线程读写;
  • finish阶段:释放MDL锁;
    1、3、4如果没有锁冲突,执行时间非常短。第2步占用了DDL绝大部分时间,这期间这个表可以正常读写数据,是因此称为“online ”。
    如果第3步升级为MDL写锁的时候,这个表的MDL锁有其他事务占着,那么这个事务会阻塞,等到可以拿到MDL写锁,而且如果不幸一直拿不到,最后锁超时了,就只好回滚这个DDL操作。
    所以,DDL语句只有才开始和结束的时候,才会禁止读和写,在语句执行的时候是可以进行读的。

写在后面

如果本文对你有帮助,请点赞收藏关注一下吧 ~
在这里插入图片描述

http://www.lryc.cn/news/37434.html

相关文章:

  • c++11 标准模板(STL)(std::unordered_map)(八)
  • 企业ISO体系认证办理,可以自行申请吗?为什么都要找咨询公司?
  • 二、Neo4j源码研究系列 - 单步调试
  • 基于Qt WebEngine 的Web仪器面板GUI程控技术
  • 海康摄像头使用RTSP
  • 编程语言分类
  • [nodejs开发] typescript引入js模块或文件
  • 小帮软件机器人应用于通信集团财务数据填报、编制、稽核、银企对账
  • 37. CF-Weights Distributing
  • 百丽时尚×优维科技×道客战略启动「云原生一体化项目」
  • 小诺开源技术
  • AidLux AI应用案例悬赏选题 | 纺织品表面瑕疵检测
  • UE官方教程笔记02-实时渲染基础下
  • grep命令——在文件中搜索指定的文本模式
  • 数据结构刷题(二十二):90子集II、491递增子序列、46全排列
  • AI+人类,实现高效网络安全
  • 牛客小白月赛68【A-E】
  • WIFI P2P架构
  • 架构师之中台思维_系统发展之路_结果和抽象之间平衡的艺术
  • 23届非科班选手秋招转码指南
  • 《传感器技术》考试学习笔记
  • 第十五章 opengl之高级OpenGL(模板测试)
  • 【C语言蓝桥杯每日一题】—— 单词分析
  • Web2:Tomcat
  • C++语法规则2(C++面向对象)
  • 第八批国家药品集中采购-(附药品集采目录明细下载)
  • 政府工作报告连提9年科技创新 企业研发如何“又快又好”
  • GM8773C 是一款 1:2 DSI 桥接芯片,可实现 4 路进 8 路出转换器功能、视频分离器功能。
  • Java常用包名和说明
  • dva01-初识