首页 > 数据库 >mysql的update更新及delete删表记录where不带索引字段导致死锁

mysql的update更新及delete删表记录where不带索引字段导致死锁

时间:2023-07-03 19:44:23浏览次数:41  
标签:语句 记录 删表 update 索引 死锁 全表 where

为什么会发生这种的事故?

InnoDB 存储引擎的默认事务隔离级别是「可重复读」,但是在这个隔离级别下,在多个事务并发的时候,会出现幻读的问题,所谓的幻读是指在同一事务下,连续执行两次同样的查询语句,第二次的查询语句可能会返回之前不存在的行。

因此 InnoDB 存储引擎自己实现了行锁,通过 next-key 锁(记录锁和间隙锁的组合)来锁住记录本身和记录之间的“间隙”,防止其他事务在这个记录之间插入新的记录,从而避免了幻读现象。

当我们执行 update 语句时,实际上是会对记录加独占锁(X 锁)的,如果其他事务对持有独占锁的记录进行修改时是会被阻塞的。另外,这个锁并不是执行完 update 语句就会释放的,而是会等事务结束时才会释放。

在 InnoDB 事务中,对记录加锁带基本单位是 next-key 锁,但是会因为一些条件会退化成间隙锁,或者记录锁。加锁的位置准确的说,锁是加在索引上的而非行上。

比如,在 update 语句的 where 条件使用了唯一索引,那么 next-key 锁会退化成记录锁,也就是只会给一行记录加锁。

这里举个例子,这里有一张数据库表,其中 id 为主键索引。

 

假设有两个事务的执行顺序如下:

 

可以看到,事务 A 的 update 语句中 where 是等值查询,并且 id 是唯一索引,所以只会对 id = 1 这条记录加锁,因此,事务 B 的更新操作并不会阻塞。

但是,在 update 语句的 where 条件没有使用索引,就会全表扫描,于是就会对所有记录加上 next-key 锁(记录锁 + 间隙锁),相当于把整个表锁住了。

假设有两个事务的执行顺序如下:

 

可以看到,这次事务 B 的 update 语句被阻塞了。

这是因为事务 A的 update 语句中 where 条件没有索引列,所有记录都会被加锁,也就是这条 update 语句产生了 4 个记录锁和 5 个间隙锁,相当于锁住了全表。

 

因此,当在数据量非常大的数据库表执行 update 语句时,如果没有使用索引,就会给全表的加上 next-key 锁, 那么锁就会持续很长一段时间,直到事务结束。

而这期间除了 ​​select ... from​​语句,其他语句都会被锁住不能执行,业务会因此停滞,接下来等着你的,就是老板的挨骂。

那 update 语句的 where 带上索引就能避免全表记录加锁了吗?

并不是。

关键还得看这条语句在执行过程中,优化器最终选择的是索引扫描,还是全表扫描,如果走了全表扫描,就会对全表的记录加锁了。

又该如何避免这种事故的发生?

我们可以将 MySQL 里的 ​​sql_safe_updates​​ 参数设置为 1,开启安全更新模式。

官方的解释:

If set to 1, MySQL aborts UPDATE or DELETE statements that do not use a key in the WHERE clause or a LIMIT clause. (Specifically, UPDATE statements must have a WHERE clause that uses a key or a LIMIT clause, or both. DELETE statements must have both.) This makes it possible to catch UPDATE or DELETE statements where keys are not used properly and that would probably change or delete a large number of rows. The default value is 0.

大致的意思是,当 sql_safe_updates 设置为 1 时。

update 语句必须满足如下条件之一才能执行成功:

使用 where,并且 where 条件中必须有索引列;
使用 limit;
同时使用 where 和 limit,此时 where 条件中可以没有索引列;
delete 语句必须满足如下条件之一才能执行成功:

使用 where,并且 where 条件中必须有索引列;
同时使用 where 和 limit,此时 where 条件中可以没有索引列;
如果 where 条件带上了索引列,但是优化器最终扫描选择的是全表,而不是索引的话,我们可以使用 ​​force index([index_name])​​ 可以告诉优化器使用哪个索引,以此避免有几率锁全表带来的隐患。

总结

不要小看一条 update 语句,在生产机上使用不当可能会导致业务停滞,甚至崩溃。

当我们要执行 update 语句的时候,确保 where 条件中带上了索引列,并且在测试机确认该语句是否走的是索引扫描,防止因为扫描全表,而对表中的所有记录加上锁。

我们可以打开 MySQL 里的 sql_safe_updates 参数,这样可以预防 update 操作时 where 条件没有带上索引列。

如果发现即使在 where 条件中带上了列索引列,优化器走的还是全标扫描,这时我们就要使用 ​​force index([index_name])​​ 可以告诉优化器使用哪个索引。

本文出自​ ​https://blog.csdn.net/qq_32323239/article/details/120535834​​

mysql的行锁是通过索引加载的,即是行锁是加在索引响应的行上的,要是对应的SQL语句没有走索引,则会全表扫描,

行锁则无法实现,取而代之的是表锁。

简而言之:where条件里面,不加索引时,update会使用“表锁”进行更新,影响所有行的查询更新;

加了索引后,使用“行锁”进行udpate,只锁当前行。不影响其他行的查询更新。

2. 为什么批量更新时会锁表
因为批量更新时,因为表中没有加索引,会检索整个表导致更新非常慢,而每条更新sql提交事务都有个超时限制 ,后提交的事务等待前面处理的事务释放锁,但是在等待的时候超过了mysql的锁等待时间,就会引发异常从而导致锁表:Lock wait timeout exceeded; try restarting transaction

本文出自​ ​https://www.bbsmax.com/A/Gkz1PGD2dR/​
-----------------------------------
mysql的update更新及delete删表记录where不带索引字段导致死锁
https://blog.51cto.com/lookingdream/4811416

标签:语句,记录,删表,update,索引,死锁,全表,where
From: https://www.cnblogs.com/sunlong88/p/17523827.html

相关文章

  • saveOrUpdate failed with new sequence number
    Domainobject:<hibernate-mapping><classname="Trade"table="Trades"><idname="seqNum"column="SEQ_NUM"type="long"><generatorclass="sequence"><par......
  • Unable to update index for central http://repo1.maven.org/maven2/
    Unable to update index for central http://repo1.maven.org/maven2/ 就是这句,myeclipse启动后控制台输出这句话:解决办法:1.在myeclipse3.4(我用的这个版本)里面Window => Preferences => Myeclipse Enterprise Workbench => Maven4Myeclipse => Maven=>禁用Downl......
  • update-alternatives 的基本用法
    update-alternatives是Ubuntu的软件多版本管理工具,基本用法为,update-alternatives--install<link><name><path><priority>[--force]例如,我要创建一个符号链接/usr/bin/cmake,它指向实际安装路径/usr/local/bin/cmake,则可以使用如下命令,sudoupdate-alternatives......
  • 【WALT】WALT入口 update_task_ravg() 代码详解
    目录【WALT】WALT入口update_task_ravg()代码详解代码展示代码逻辑⑴ 判断是否进入WALT算法⑵ 获取WALT算法中上一个窗口的开始时间⑶如果任务刚初始化结束⑷ 更新任务及CPU的cycles⑸ 更新任务及CPU的demand及pred_demand⑹ 更新CPU的busytime⑺ 更新任务的p......
  • 【WALT】update_window_start() 代码详解
    目录【WALT】update_window_start()代码详解代码展示代码逻辑【WALT】update_window_start()代码详解代码版本:Linux4.9android-msm-crosshatch-4.9-android12代码展示staticu64update_window_start(structrq*rq,u64wallclock,intevent){ s64delta; intnr_window......
  • Windows Server 2022 中文版、英文版下载 (updated Jun 2023)
    WindowsServer2022中文版、英文版下载(updatedJun2023)WindowsServer2022正式版,2023年6月更新请访问原文链接:https://sysin.org/blog/windows-server-2022/,查看最新版。原创作品,转载请保留出处。作者主页:sysin.org早期直观体验版本21H2,根据名称预计今年秋季......
  • Windows 10, version 22H2 (updated Jun 2023) 中文版、英文版下载
    Windows10,version22H2(updatedJun2023)中文版、英文版下载Windows1022H2企业版arm64x64请访问原文链接:https://sysin.org/blog/windows-10/,查看最新版。原创作品,转载请保留出处。作者主页:sysin.orgWindows10更新历史记录Windows10,version22H2,alledit......
  • Windows 11 22H2 中文版、英文版 (x64、ARM64) 下载 (updated Jun 2023)
    Windows1122H2中文版、英文版(x64、ARM64)下载(updatedJun2023)Windows11,version22H2,2023年6月更新请访问原文链接:https://sysin.org/blog/windows-11/,查看最新版。原创作品,转载请保留出处。作者主页:sysin.org全新推出Windows11全新Windows体验,让您与热......
  • 如何避免热度数据频繁更新造成数据库死锁?
    数据库死锁对业务来说是一个非常严重的问题,它一定一定一定是代码的执行流程处理不当造成的。但是重构庞大的业务代码不是说了就能轻易做到的事情,下面给出了一些方案,由浅入深,告诉大家解决死锁问题的正确之道。死锁问题产生的原因和条件死锁问题一般发生在短时间内多个并发任务对同一......
  • 如何禁用 Microsoft AutoUpdate
    在桌面使用快捷键:command(⌘)+⇧+G输入以下内容/Library/ApplicationSupport/Microsoft/并按回车删除文件夹MAU2.0即可参考自:https://xie.infoq.cn/article/ab0f47525943dfb1b603ce2ad......