update的where条件要把索引的字段带上,要不然就全表锁
update的where条件要把索引的字段带上,要不然就全表锁
文章目录
update的where条件要把索引的字段带上,要不然就全表锁
本文主要内容
背景
在学习中总结一下内容
关于锁的表
sql加锁思考点
InnoDB行锁实现方式
本文主要内容
报错了: java.sql.BatchUpdateException: Lock wait timeout exceeded; try restarting transaction
对表进行更新和插入操作,在update的时候出现上述异常,经过排查发现是锁表的原因。
背景
建表语句如下:
表名为: app_pay_log_test
索引为:UNIQUE KEY rso_orderid_idx (rso,order_id)
CREATE TABLE `app_pay_log_test` (
`rso` varchar(50) NOT NULL DEFAULT '-1' COMMENT '充值渠道',
`order_id` varchar(100) NOT NULL COMMENT '订单id',
`amount` decimal(20,2) NOT NULL COMMENT '充值金额',
`product` varchar(50) DEFAULT NULL,
UNIQUE KEY `rso_orderid_idx` (`rso`,`order_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='手游充值订单';
1
2
3
4
5
6
7
出现异常的执行操作为:
UPDATE `app_pay_log_test` SET `product`=$2 WHERE `order_id`=$1 AND `product` is NULL
1
这里全表扫描锁表了,update的where条件把索引的字段要带上,要不然就全表锁。
也就是说要把检索条件上加上索引。而本表的索引是联合索引,上面的sql没有走索引,导致去全表扫描,出现表锁。
解决办法:
UPDATE `app_pay_log_test` SET `product`=$2 WHERE `rso`=$0 AND `order_id`=$1 AND `product` is NULL
1
实际上,不管是插入更新查询都需要走索引才不会那么容易出现全表扫描。
在学习中总结一下内容
InnoDB行锁是通过给索引上的索引项加锁来实现的。
InnoDB这种行锁实现特点意味着:只有通过索引条件检索数据,InnoDB才使用行级锁,否则,InnoDB将使用表锁!
在实际应用中,要特别注意InnoDB行锁的这一特性,不然的话,可能导致大量的锁冲突,从而影响并发性能。
关于锁的表
由于MySQL的行锁是针对索引加的锁,不是针对记录加的锁,所以虽然是访问不同行的记录,但是如果是使用相同的索引键,是会出现锁冲突的。
MySQL 5.5 中,information_schema库中新增了三个关于锁的表,即 innodb_trx、innodb_locks 和 innodb_lock_waits.
其中 innodb_trx 表记录当前运行的所有事务,innodb_locks 表记录当前出现的锁,innodb_lock_waits 表记录锁等待的对应关系。
具体用法可以参考:表结构说明
SELECT * FROM information_schema.INNODB_TRX\G;
SELECT * FROM information_schema.innodb_locks \G
SELECT * FROM information_schema.innodb_lock_waits \G
1
2
3
在 innodb_trx 表的第一行,trx_id为360F表示事务id,状态(trx_state)为等待状态,线程ID为2,事务用到的表为1(trx_tables_in_use),有1(trx_tables_locked)个表被锁。可以使用 kill trx_mysql_thread_id 杀死这个sql线程。
mysql> SELECT * FROM information_schema.innodb_trx \G
*************************** 1. row ***************************
trx_id: 360F
trx_state: LOCK WAIT
trx_mysql_thread_id: 2
trx_query: UPDATE user SET name="lock_waits" WHERE ID = 2
trx_tables_in_use: 1
trx_tables_locked: 1
1
2
3
4
5
6
7
8
sql加锁思考点
前提一:筛选列是不是主键?
前提二:当前系统的隔离级别是什么?(不同隔离级别 锁类型不同)
前提三:筛选列如果不是主键,那么筛选列上有索引吗?
前提四:筛选列上如果有二级索引,那么这个索引是唯一索引吗?(唯一索引只锁一行)
前提五:两个SQL的执行计划是什么?索引扫描?全表扫描?(走行锁还是表锁或者间隙锁)
InnoDB行锁实现方式
InnoDB行锁是通过给索引上的索引项加锁来实现的,只有通过索引条件检索数据,InnoDB才使用行级锁,否则,InnoDB将使用表锁
在实际应用中,要特别注意InnoDB行锁的这一特性,不然的话,可能导致大量的锁冲突,从而影响并发性能。下面通过一些实际例子来加以说明。
(1)在不通过索引条件查询的时候,InnoDB确实使用的是表锁,而不是行锁。
(2)由于MySQL的行锁是针对索引加的锁,不是针对记录加的锁,所以虽然是访问不同行的记录,但是如果是使用相同的索引键,是会出现锁冲突的。
(3)当表有多个索引的时候,不同的事务可以使用不同的索引锁定不同的行,另外,不论是使用主键索引、唯一索引或普通索引,InnoDB都会使用行锁来对数据加锁。
(4)即便在条件中使用了索引字段,但是否使用索引来检索数据是由MySQL通过判断不同执行计划的代价来决定的,如果MySQL认为全表扫描效率更高,比如对一些很小的表,它就不会使用索引,这种情况下InnoDB将使用表锁,而不是行锁。因此,在分析锁冲突时,别忘了检查SQL的执行计划,以确认是否真正使用了索引。
参考:
MySQL SHOW PROCESSLIST协助故障诊断 http://www.ywnds.com/?p=9337
记一次数据库死锁Deadlock https://www.jianshu.com/p/1c8fecb00563
MySQL 5.5 InnoDB 锁等待 https://dbarobin.com/2015/01/27/innodb-lock-wait-under-mysql-5.5/
————————————————
版权声明:本文为CSDN博主「Agly_Charlie」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/Agly_Clarlie/article/details/83032289
update的where条件要把索引的字段带上,要不然就全表锁的更多相关文章
- 【从翻译mos文章】采用高速全扫描索引(index ffs) 为了避免全表扫描
采用高速全扫描索引(index ffs) 为了避免全表扫描 参考原始: Index Fast Full Scan Usage To Avoid Full Table Scans (Doc ID 701 ...
- update当根据条件不同时 更新同一个字段的方法 或多表插入
1.通过存储过程 循环 传值 create or replace procedure p_u isbegin for rs in (select distinct (rks) from rkbz)lo ...
- 陷阱~SQL全表扫描与聚集索引扫描
SqlServer中在查询时,我们为了优化性能,通常会为where条件的字段建立索引,如果条件比较固定还会建立组合索引,接下来,我们来看一下索引与查询的相关知识及相关陷阱. SQL表自动为主键加聚集索 ...
- 索引法则--LIKE以%开头会导致索引失效进而转向全表扫描(使用覆盖索引解决)
Mysql 系列文章主页 =============== 1 准备数据 1.1 建表 DROP TABLE IF EXISTS staff; CREATE TABLE IF NOT EXISTS st ...
- mysql 全表扫描、全索引扫描、索引覆盖(覆盖索引)
full index scan:全索引扫描,查询时,遍历索引树来获取数据行.如果数据不是密集的会产生随机IO 在执行计划中是Type列,index full table scan:通过读物理表获取数据 ...
- MySQL中的全表扫描和索引树扫描
引言 在学习mysql时,我们经常会使用explain来查看sql查询的索引等优化手段的使用情况.在使用explain时,我们可以观察到,explain的输出有一个很关键的列,它就是type属性,ty ...
- SQL 语句调优 where 条件 数据类型 临时表 索引
基本原则 避免全表扫描 建立索引 尽量避免向客户端返回大数据量,若数据量过大,应该考虑相应需求是否合理 尽量避免大事务操作,提高系统并发能力 使用基于游标的方法或临时表方法之前,应先寻找基于集的解决方 ...
- 不恰当的update语句使用主键和索引导致mysql死锁
背景知识: 截至目前,MySQL一共向用户提供了包括DBD.HEAP.ISAM.MERGE.MyIAS.InnoDB以及Gemeni这7种Mysql表类型.其中DBD.InnoDB属于事务安全类表,而 ...
- mysql 通过测试'for update',深入了解行锁、表锁、索引
mysql 通过测试'for update',深入了解行锁.表锁.索引 条件 FOR UPDATE 仅适用于InnoDB存储引擎,且必须在事务区块(BEGIN/COMMIT)中才能生效. mysql默 ...
随机推荐
- 【2019.7.15 NOIP模拟赛 T2】与非树(nand)(树形DP)
树形\(DP\) 实际上,这道题应该不是很难. 我们设\(f_{x,i,j}\)表示在以\(x\)为根的子树内,原本应输出\(i\),结果输出了\(j\)的情况数. 转移时,为了方便,我们先考虑与,再 ...
- 配置中心Apollo实战
Apollo(阿波罗)是携程框架部门研发的分布式配置中心,能够集中化管理应用不同环境.不同集群的配置,配置修改后能够实时推送到应用端,并且具备规范的权限.流程治理等特性,适用于微服务配置管理场景. 服 ...
- Metasploit 常用命令手册
Installation curl https://raw.githubusercontent.com/rapid7/metasploit-omnibus/master/config/template ...
- 团队作业第五次—项目冲刺-Day7
Day7 part1-SCRUM: 项目相关 作业相关 具体描述 所属班级 2019秋福大软件工程实践Z班 作业要求 团队作业第五次-项目冲刺 作业正文 hunter--冲刺集合 团队名称 hunte ...
- 微信企业号获取OpenID过程
define('CorpID', "wx82e2c31215d9a5a7"); define('CorpSecret', ""); //当前管理组 设置-> ...
- mysql的varchar和oracle的varchar2、nvarchar2
mysql的varchar长度表示字符长度,一个汉字和一个英文字母的长度都是1 实例:下面name字段定义为varchar(10),可存10个汉字和10个字母 oracle的varchar2长度表示的 ...
- sync 异步编程
using System; using System.Net; using System.Threading; using System.Threading.Tasks; namespace Cons ...
- 在 C++ 中使用 QML 对象
看过了如何在 QML 中使用 C++ 类型或对象,现在来看如何在 C++ 中使用 QML 对象. 我们可以使用 QML 对象的信号.槽,访问它们的属性,都没有问题,因为很多 QML 对象对应的类型,原 ...
- [数据库] SQL 语法之进阶篇
一.创建计算字段 下面介绍什么是计算字段,如何创建计算字段,以及如何从应用程序中使用别名引用它们. 1.1 计算字段 存储在数据库表中的数据一般不是应用程序所需要的格式,下面举几个例子. 需要显示公司 ...
- solr常见错误
这两天给客户部署独立的solr服务器遇到的错误,现在总结一下. 1. org.apache.solr.client.solrj.SolrServerException: Error executing ...