update加锁分析:是加行锁还是表锁?具体加锁加哪儿?

InnoDB默认事务的隔离级别是可重复读。在可重复读的情况下,会出现幻读的情况。幻读就是同一事务下,两次连续查询的结果不一致,会返回之前不存在的行。

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

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

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

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

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

因此,当在数据量非常大的数据库表执行 update 语句时,如果没有使用索引,就会给全表的加上 next-key 锁, 那么锁就会持续很长一段时间,直到事务结束。而这期间除了 select ... from 语句,其他语句都会被锁住不能执行。

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

关键还得看这条语句在执行过程中,优化器最终选择的是索引扫描,还是全表扫描,如果走了全表扫描,就会对全表的记录加锁了。我们可以将 MySQL 里的 sql_safe_updates 参数设置为 1,开启安全更新模式。

大致的意思是,当 sql_safe_updates 设置为 1 时,update 语句必须满足如下条件之一才能执行成功:

  • 使用 where,并且 where 条件中必须有索引列。
  • 使用 limit。
  • 同时使用 where 和 limit,此时 where 条件中可以没有索引列。

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

  • 使用 where,并且 where 条件中必须有索引列。
  • 同时使用 where 和 limit,此时 where 条件中可以没有索引列。

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

总结:当我们要执行 update 语句的时候,确保 where 条件中带上了索引列,并且在测试机确认该语句是否走的是索引扫描,防止因为扫描全表,而对表中的所有记录加上锁。我们可以打开 MySQL 里的 sql_safe_updates 参数,这样可以预防 update 操作时 where 条件没有带上索引列。如果发现即使在 where 条件中带上了列索引列,优化器走的还是全标扫描,这时我们就要使用 force index([index_name]) 可以告诉优化器使用哪个索引。

  • 6
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值