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. SQL中group by的注意事项

    最最最最重要的: group by有一个原则,就是select后面所有的列中,没有使用聚合函数的列,必须出现在group by子句中. group by子句中的注意事项: 1,不能使用别名(因为执行顺 ...

  2. workerman docker 运行试用

    看到别人项目使用了workerman 作为webserver ,看了下介绍发现此框架还是挺强大的,比较喜欢使用 docker运行软件,所以基于php 7.3 的基础镜像简单使用下 环境准备 项目使用了 ...

  3. Attention篇(二)

    主要是对<Attention is all you need>的分析 结合:http://www.cnblogs.com/robert-dlut/p/8638283.html  以及自己的 ...

  4. 第02组 Beta冲刺(4/4)

    队名:十一个憨批 组长博客 作业博客 组长黄智 过去两天完成的任务:了解整个游戏的流程 GitHub签入记录 接下来的计划:继续完成游戏 还剩下哪些任务:完成游戏 燃尽图 遇到的困难:没有美术比较好的 ...

  5. 使用阿里云OSS上传文件

    本文介绍如何利用Java API操作阿里云OSS对象存储. 1.控制台操作 首先介绍一下阿里云OSS对象存储的一些基本概念. 1.1 进入对象存储界面 登录阿里云账号,进入对象存储界面,如图所示. 进 ...

  6. 收藏一份devmem源码

    /* * devmem2.c: Simple program to read/write from/to any location in memory. * * Copyright (C) 2000, ...

  7. HTML+css基础 p段落标签 a 超链接标签 Src和href有什么区别和关联? target属性 Meta标签

    p段落标签: <p></p> 1.他是唯一一个可以不写结束标签的双标签. a 超链接标签: 从一个页面链接到另一个页面.靠的是href属性.  Src和href有什么区别和关联 ...

  8. SQLServer查看分区表详细信息

    SQL查看分区内记录个数,常规方法需要知道分区函数然后再显示,网上看到一个一句话显示的方法 ), ps.name ) as partition_scheme, p.partition_number, ...

  9. 在 ubuntu 下安装 mono 和 xsp4 ,并测试

    1. 安装完 ubuntu 后,在 ubuntu 软件中查看是否自带了 mono 运行时和 XSP4,如果没有,则选中后,点击安装按钮. 2. 安装完后,在终端(类似于 Windows 上的命令行工具 ...

  10. mongodb 更新数据时int32变为double的解决办法

       场景: 在命令手动的修改签到表的整型字段synState,multi参数是可以更新多条,如果是false则更新一条. db.getCollection("ClassRecordOneD ...