03.11 Day 52 - insert 语句

大家好,我是 Snow Hide,作为《MySQL 实战》这个专栏的学员之一,这是我打卡的第 52 天,也是我第 114 次进行这种操作。

今天我温习了该专栏里一篇叫《insert语句的锁为什么这么多?》的文章。

关键词总结:insert … select 语句(可重复读隔离级别下 binlog_format 为 statement 时执行插入操作时需要对表的所有行和间隙加锁)、insert 循环写入(循环插入语句执行过程、用临时表做优化)、insert 唯一键冲突(会话一执行回滚时会话三几乎同时发现死锁并返回的逻辑)、insert into … on duplicate key update(该语句的语义逻辑)。

所学总结:

insert … select 语句

可重复读隔离级别下 binlog_format 为 statement 时执行插入操作时需要对表的所有行和间隙加锁

  • 实际的执行效果是当会话二先执行时,由于该语句对表 t 主键索引加了 next-key lock,会在语句执行完成后,才允许会话一的 insert 语句执行;
  • 但如果没有锁的话,就会出现会话二的 insert 语句先执行,但事后写入 binlog 的情况。于是,在 binlog_format=statement 的情况下,binlog 里就记录了这样的语句序列:
insert into t values(-1,-1,-1);
insert into t2(c,d) select c,d from t;

insert 循环写入

insert into t(c,d)  (select c+1, d from t force index(c) order by c desc limit 1);

循环插入语句执行过程

  1. 创建有 c 和 d 两个字段的临时表;
  2. 按照索引 c 扫描表 t,依次取 c=4、3、2、1,然后回表,读到 c 和 d 的值写入临时表。此时 Rows_examined=4;
  3. 由于语义里有 limit 1,所以只取了临时表的第一行,再插入到表 t 中。这时 Rows_examined 的值加 1,变成了 5。

用临时表做优化

由于这个语句设计的数据量很小,可以考虑用内存临时表来做这个优化:

create temporary table temp_t(c int,d int) engine=memory;
insert into temp_t  (select c+1, d from t force index(c) order by c desc limit 1);
insert into t select * from temp_t;
drop table temp_t;

insert 唯一键冲突

会话一执行回滚时会话三几乎同时发现死锁并返回的逻辑

  1. 在事务一时启动会话一并执行 insert 语句,此时在索引 c 的 c=5 上加了记录锁。该索引是唯一索引,因此退化为记录锁;
  2. 在事务二时会话二要执行相同的 insert 语句,发现了唯一键冲突,加上读锁;同样地,会话三也在索引 c 上,c=5 记录上,加了读锁;
  3. 事务三时会话一回滚。这时会话二和会话三都试图继续执行插入操作,都要加上写锁。两个会话都要等待对方的行锁,所以就出现了死锁。
     

insert into … on duplicate key update

insert into t values(11,10,10) on duplicate key update d=100; 

该语句的语义逻辑

插入一行数据,当碰到唯一键约束就执行后面的更新语句。

末了

重新总结了一下文中提到的内容:insert … select 是很常见的在两表之间拷贝数据的方法、insert 和 select 的对象是同一个表时可能会造成循环写入、insert 语句如果出现唯一键冲突,会在冲突的唯一值上加共享的 next-key lock。

发布了224 篇原创文章 · 获赞 13 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/stevenchen1989/article/details/104788534
今日推荐