update 没有索引导致业务崩了,老板骂了一个小时
摘要:有天,一朋友在线上执行一条 update 语句修改数据库数据的时候,where 条件没有带上索引,导致业务直接崩了,被老板教训了一波。
本文分享自华为云社区《update 没有索引,会锁全表!》,作者: 小林coding 。
有天,一朋友在线上执行一条 update 语句修改数据库数据的时候,where 条件没有带上索引,导致业务直接崩了,被老板教训了一波。
这次我们就来看看:
- 为什么会发生这种的事故?
- 又该如何避免这种事故的发生?
说个前提,接下来说的案例都是基于 InnoDB 存储引擎,且事务的隔离级别是可重复读。
为什么会发生这种的事故?
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]) 可以告诉优化器使用哪个索引。
这次就说到这啦,下次要小心点,别再被老板挨骂啦。
update 没有索引导致业务崩了,老板骂了一个小时的更多相关文章
- 【故障处理141119】一次数据库不繁忙时一条sql语句2个运行计划导致业务超时的故障处理
1,故障描写叙述: 一条select有两个运行计划.在sqlplus中运行选择好的运行计划.仅仅要40毫秒.而在程序中运行选择了差的运行计划,要1分23秒左右,导致前台业务超时报错. 2.故障解决: ...
- 【生产问题】--8KW的数据表导致业务卡顿
问题描述:业务突然变得巨卡 分析思路: (1)分析用户请求进程:查看是否有长期运行霸占锁的情况,或者进程数量巨多.很明显我这里就是巨多,正常情况一般0~40来个的样子,在业务使用高峰期居然达到了140 ...
- MySQL选错索引导致的线上慢查询事故
前言 又和大家见面了!又两周过去了,我的云笔记里又多了几篇写了一半的文章草稿.有的是因为质量没有达到预期还准备再加点内容,有的则完全是一个灵感而已,内容完全木有.羡慕很多大佬们,一周能产出五六篇文章, ...
- MSSql Server 索引'uq_f_userName' 依赖于 列'f_userName'。由于一个或多个对象访问此列,ALTER TABLE ALTER COLUMN f_userName 失败
--需求有变,需要往t_login表的f_userName字段添加外国人名,之前设置的varchar(10)不够,商议决定改成varchar(30),执行的时候,提示消息 索引'uq_f_userNa ...
- 在Web.Config文件中使用configSource,避免动态修改web.config导致asp.net重启(另添加一个Config文件用于管理用户数据)
原文:在Web.Config文件中使用configSource,避免动态修改web.config导致asp.net重启(另添加一个Config文件用于管理用户数据) 我们都知道,在asp.net中修改 ...
- 不恰当的update语句使用主键和索引导致mysql死锁
背景知识: 截至目前,MySQL一共向用户提供了包括DBD.HEAP.ISAM.MERGE.MyIAS.InnoDB以及Gemeni这7种Mysql表类型.其中DBD.InnoDB属于事务安全类表,而 ...
- mysql-不恰当的update语句使用主键和索引导致mysql死锁
背景知识:MySQL有三种锁的级别:页级.表级.行级. MyISAM和MEMORY存储引擎采用的是表级锁(table-level locking):BDB存储引擎采用的是页面锁(page-level ...
- update layer tree导致页面卡顿
前因 今天检查一个vue页面问题,就是在切换Tab时候(某些win10电脑),页面会卡顿一段很长的时间,短则3秒,长则十几秒,这个体验非常糟糕,于是我着手寻找其中原因. 概况 这个vue页面的元素非常 ...
- 没有索引导致的DIRECT PATH READ
5月20号下午4-5点,某项目组进行数据入库作业,作业人员反映入库速度很慢.在16:30和16:50分别采集了快照,并根据两个快照得到AWR报告. 直接看TOP 5 EVENTS,这是数据库问题诊断的 ...
- mysql 5.6 read-committed隔离级别下并发插入唯一索引导致死锁一例
今天,某个环境又发生了死锁,如下: *** (1) TRANSACTION:TRANSACTION 735307073, ACTIVE 0 sec insertingmysql tables in u ...
随机推荐
- Chromium GPU资源共享
资源共享指的是在一个 Context 中的创建的 Texture 资源可以被其他 Context 所使用.一般来讲只有相同 share group Context 创建的 Texture 才可以被共享 ...
- 文心一言 VS 讯飞星火 VS chatgpt (124)-- 算法导论10.5 5题
五.用go语言,给定一个n结点的二叉树,写出一个 O(n)时间的非递归过程,将该树每个结点的关键字输出.要求除该树本身的存储空间外只能使用固定量的额外存储空间,且在过程中不得修改该树,即使是暂时的修改 ...
- video.js 视频
http://www.cnblogs.com/lechenging/p/3858181.html
- APP攻防--安卓逆向&数据修改&逻辑修改&视图修改
APP攻防--安卓逆向&数据修改&逻辑修改&视图修改 @ 目录 APP攻防--安卓逆向&数据修改&逻辑修改&视图修改 工具集 apk目录意义 逆向数据修 ...
- JVM-JVM如何加载类
一.Java 语言的类型可以分为两大类: 基本类型(primitive types) 引用类型(reference types):类.接口.数组类和泛型参数(泛型参数会在编译中被擦除),因此Java虚 ...
- C语言中strchr()和index()
一. C标准的一些问题 在ubuntu下rindex()函数使用没有问题,在minGW下会报错,undefined reference to `rindex',warning: implicit de ...
- 仅需三行代码! C# 快速实现PDF转PPT
一般在会议.教学或培训活动中,我们都会选择PPT文档来进行内容展示.与PDF文档相比,PPT文档具有较强的可编辑性,可以随时增删元素,并且还可以设置丰富多样的动画效果来吸引观众注意.那么如何通过C#将 ...
- 赛意SMOM和金蝶云星空单据接口对接
赛意SMOM和金蝶云星空单据接口对接 数据源系统:金蝶云星空 金蝶K/3Cloud在总结百万家客户管理最佳实践的基础上,提供了标准的管理模式:通过标准的业务架构:多会计准则.多币别.多地点.多组织.多 ...
- Codeforces Round #656 (Div. 3) E. Directing Edges(拓扑排序)
题目传送门 首先发现初始图五有向环的话那么肯定是"YES",否则是"NO".然后找到一种满足要求地建树规则即可.这里采用拓扑排序建树,先dfs找出目前点的拓扑序 ...
- 【LOJ NOI Round#2 Day1 T1】单枪匹马(矩阵乘法)
题目传送门 操作二要求的东西是一个循环迭代的东西,手推相邻两项找下规律,发现相邻两项的分子分母间含有线性关系,考虑用矩阵乘法求解.对于 \([1,n]\)的询问,从后往前倒推, \(x_{n-1}=a ...