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条件要把索引的字段带上,要不然就全表锁的更多相关文章

  1. 【从翻译mos文章】采用高速全扫描索引(index ffs) 为了避免全表扫描

    采用高速全扫描索引(index ffs) 为了避免全表扫描 参考原始: Index Fast Full Scan Usage To Avoid Full Table Scans (Doc ID 701 ...

  2. update当根据条件不同时 更新同一个字段的方法 或多表插入

    1.通过存储过程 循环 传值 create or replace procedure p_u isbegin for rs in (select distinct (rks) from rkbz)lo ...

  3. 陷阱~SQL全表扫描与聚集索引扫描

    SqlServer中在查询时,我们为了优化性能,通常会为where条件的字段建立索引,如果条件比较固定还会建立组合索引,接下来,我们来看一下索引与查询的相关知识及相关陷阱. SQL表自动为主键加聚集索 ...

  4. 索引法则--LIKE以%开头会导致索引失效进而转向全表扫描(使用覆盖索引解决)

    Mysql 系列文章主页 =============== 1 准备数据 1.1 建表 DROP TABLE IF EXISTS staff; CREATE TABLE IF NOT EXISTS st ...

  5. mysql 全表扫描、全索引扫描、索引覆盖(覆盖索引)

    full index scan:全索引扫描,查询时,遍历索引树来获取数据行.如果数据不是密集的会产生随机IO 在执行计划中是Type列,index full table scan:通过读物理表获取数据 ...

  6. MySQL中的全表扫描和索引树扫描

    引言 在学习mysql时,我们经常会使用explain来查看sql查询的索引等优化手段的使用情况.在使用explain时,我们可以观察到,explain的输出有一个很关键的列,它就是type属性,ty ...

  7. SQL 语句调优 where 条件 数据类型 临时表 索引

    基本原则 避免全表扫描 建立索引 尽量避免向客户端返回大数据量,若数据量过大,应该考虑相应需求是否合理 尽量避免大事务操作,提高系统并发能力 使用基于游标的方法或临时表方法之前,应先寻找基于集的解决方 ...

  8. 不恰当的update语句使用主键和索引导致mysql死锁

    背景知识: 截至目前,MySQL一共向用户提供了包括DBD.HEAP.ISAM.MERGE.MyIAS.InnoDB以及Gemeni这7种Mysql表类型.其中DBD.InnoDB属于事务安全类表,而 ...

  9. mysql 通过测试'for update',深入了解行锁、表锁、索引

    mysql 通过测试'for update',深入了解行锁.表锁.索引 条件 FOR UPDATE 仅适用于InnoDB存储引擎,且必须在事务区块(BEGIN/COMMIT)中才能生效. mysql默 ...

随机推荐

  1. ASP.NET Core MVC 中的 Model 模型

    ASP.NET Core MVC 中的 Model 我们希望最终从 Student 数据库表中查询特定的学生详细信息并显示在网页上,如下所示. MVC 中的模型包含一组表示数据的类和管理该数据的逻辑. ...

  2. [LeetCode] 738. Monotone Increasing Digits 单调递增数字

    Given a non-negative integer N, find the largest number that is less than or equal to N with monoton ...

  3. Navicat Keygen - for Windows

    如何使用这个注册机 从这里下载最新的release. 使用navicat-patcher.exe替换掉navicat.exe和libcc.dll里的Navicat激活公钥. navicat-patch ...

  4. 微信小程序起步

    微信小程序 文档 微信小程序开发文档 本质 so微信小程序到底是什么?是原生的app还是H5应用? 简单来说,小程序是一种应用,运行的环境是微信(App)进程中,使用了部分的H5技术 目录介绍 app ...

  5. 关于优秀的视频播放器 - PotPlayer

    播放器设置 直接截图: 其他重要功能 1. 切换语音:Alt + A 谢谢浏览!

  6. 图解微信小程序---获取电影信息

    图解微信小程序---获取电影信息 代码笔记 第一步:编写js文件,调用api获取相对应电影详情信息(注意带入的参数是id不在是榜单的type,电影api的movie后面又斜杠,别忘了,对应的绑定数据的 ...

  7. 前端面试01:描述一下cookices sessionStorage 和 localStorage 的区别

    相同点:都可以存储在客户端 不同点: 1.存储大小 cookie数据大小不能超过4K. sessionStorage 和 localStorage 虽然也有大小限制,但是比cookie大得多,可以达到 ...

  8. 用友U9 基础使用文件所在目录

    元数据存主位置 D:\yonyou\UBFV50\U9.VOB.Product.Metadata 日志文件位置 D:\yonyou\U9V50\Portal\log UI热插支持文件 D:\yonyo ...

  9. oracle 自增序列实现 可作为主键

    好记性不如烂笔头 记录如何建立oracle 自增序列 表结构 create table TAB_USERINPUT ( RID VARCHAR2(20) not null, VARID VARCHAR ...

  10. SVN服务端安装和仓库的创建

    1.安装SVN服务端 双击运行: 点击[next] 勾上复选框,点击[next] 使用默认选项,点击[next] 点击[Standard Edition]建议端口号不用443,因为Vmware占用了, ...