深入研究insert into select语句锁表故障(上)

故障描述

前几天,一个mysql数据库运维同事,在生产上用insert into select * from语句,在生产上备份了一张表,结果将备份表全表锁住了,业务影响了大约10分钟。
看到这个语句,我第一反应就是select语句也能锁表,可是生产上的故障,证明确实锁表了。所以,需要将insert into select * from获取锁的情况彻底研究明白。

故障复盘

创建模拟表和模拟记录

[root@localhost] 17:39:55 [testdb1]>show create table t_test_1\G;
*************************** 1. row ***************************Table: t_test_1
Create Table: CREATE TABLE `t_test_1` (`id` int(11) NOT NULL,`name` char(10) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
1 row in set (0.00 sec)[root@localhost] 17:40:30 [testdb1]>select * from t_test_1;
+----+-------+
| id | name  |
+----+-------+
|  1 | trest |
|  2 | e99e  |
|  3 | test  |
|  4 | fresd |
|  5 | fsfa  |
+----+-------+
5 rows in set (0.00 sec)[root@localhost] 17:40:17 [testdb1]>show create table t_test_2\G;
*************************** 1. row ***************************Table: t_test_2
Create Table: CREATE TABLE `t_test_2` (`id` int(11) NOT NULL,`name` char(10) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
1 row in set (0.00 sec)

模拟insert into select操作

[root@localhost] 17:41:32 [testdb1]>begin;
Query OK, 0 rows affected (0.00 sec)[root@localhost] 17:41:33 [testdb1]>insert into t_test_2 select * from t_test_1 where name like 'trest';
Query OK, 1 row affected (0.02 sec)
Records: 1  Duplicates: 0  Warnings: 0

获取innodb的lock信息

[root@localhost] 17:42:00 [(none)]>show engine innodb status\G;
TRANSACTIONS
------------
Trx id counter 182551
Purge done for trx's n:o < 182551 undo n:o < 0 state: running but idle
History list length 0
LIST OF TRANSACTIONS FOR EACH SESSION:
---TRANSACTION 421524582451936, not started
0 lock struct(s), heap size 1136, 0 row lock(s)
---TRANSACTION 182546, ACTIVE 20 sec
3 lock struct(s), heap size 1136, 6 row lock(s), undo log entries 1
MySQL thread id 7, OS thread handle 140049254979328, query id 82 localhost root

从innodb引擎获取的lock信息,太少了,只能看到有3 lock struct(s),6 row lock(s),不清楚那表申请的锁,申请什么类型的锁,不知道这些信息,就研究不明白故障到底怎么发生的。

幸运的是,mysql数据库提供一个参数innodb_status_output_locks,可以打印更详细的lock信息。

启用innodb_status_output_locks参数

启用innodb_status_output_locks参数,默认是不开启,所以需要开启。

[root@localhost] 17:31:12 [(none)]>show variables like 'innodb_status_output_locks';
+----------------------------+-------+
| Variable_name              | Value |
+----------------------------+-------+
| innodb_status_output_locks | OFF   |
+----------------------------+-------+
1 row in set (0.00 sec)[root@localhost] 17:47:41 [(none)]>set global innodb_status_output_locks=on;
Query OK, 0 rows affected (0.00 sec)[root@localhost] 17:47:41 [(none)]>show variables like 'innodb_status_output_locks';
+----------------------------+-------+
| Variable_name              | Value |
+----------------------------+-------+
| innodb_status_output_locks | ON    |
+----------------------------+-------+
1 row in set (0.00 sec)

获取innodb的lock详细信息
下面是开启innodb_status_output_locks参数之后,获取的详细lock信息

[root@localhost] 17:48:28 [(none)]>show engine innodb status\G;
TRANSACTIONS
------------
Trx id counter 182552
Purge done for trx's n:o < 182551 undo n:o < 0 state: running but idle
History list length 0
LIST OF TRANSACTIONS FOR EACH SESSION:
---TRANSACTION 421524582451936, not started
0 lock struct(s), heap size 1136, 0 row lock(s)
---TRANSACTION 182551, ACTIVE 5 sec
3 lock struct(s), heap size 1136, 6 row lock(s), undo log entries 1
MySQL thread id 11, OS thread handle 140049254979328, query id 100 localhost root
TABLE LOCK table `testdb1`.`t_test_1` trx id 182551 lock mode IS
RECORD LOCKS space id 97 page no 3 n bits 72 index PRIMARY of table `testdb1`.`t_test_1` trx id 182551 lock mode S
Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 00: len 8; hex 73757072656d756d; asc supremum;;Record lock, heap no 2 PHYSICAL RECORD: n_fields 4; compact format; info bits 00: len 4; hex 80000001; asc     ;;1: len 6; hex 00000002c710; asc       ;;2: len 7; hex af000000310110; asc     1  ;;3: len 10; hex 74726573742020202020; asc trest     ;;Record lock, heap no 3 PHYSICAL RECORD: n_fields 4; compact format; info bits 00: len 4; hex 80000002; asc     ;;1: len 6; hex 00000002c710; asc       ;;2: len 7; hex af00000031011c; asc     1  ;;3: len 10; hex 65393965202020202020; asc e99e      ;;Record lock, heap no 4 PHYSICAL RECORD: n_fields 4; compact format; info bits 00: len 4; hex 80000003; asc     ;;1: len 6; hex 00000002c710; asc       ;;2: len 7; hex af000000310128; asc     1 (;;3: len 10; hex 74657374202020202020; asc test      ;;Record lock, heap no 5 PHYSICAL RECORD: n_fields 4; compact format; info bits 00: len 4; hex 80000004; asc     ;;1: len 6; hex 00000002c710; asc       ;;2: len 7; hex af000000310134; asc     1 4;;3: len 10; hex 66726573642020202020; asc fresd     ;;Record lock, heap no 6 PHYSICAL RECORD: n_fields 4; compact format; info bits 00: len 4; hex 80000005; asc     ;;1: len 6; hex 00000002c710; asc       ;;2: len 7; hex af000000310140; asc     1 @;;3: len 10; hex 66736661202020202020; asc fsfa      ;;TABLE LOCK table `testdb1`.`t_test_2` trx id 182551 lock mode IX

从上面的信息,可以很清晰看到,t_test_1获取到IS锁,并且有5个Record lock信息,即锁了5条记录,而此表只有5条记录,所以锁全表。
TABLE LOCK table testdb1.t_test_1 trx id 182551 lock mode IS

锁全表解决方案

insert into t_test_2 select * from t_test_1 where name like ‘trest’;这个sql语句中,t_test_1表的name字段没有索引,索引走了全表扫描,如果在name字段创建索引呢,会有什么变化呢
创建索引

[root@localhost] 17:54:33 [testdb1]>alter table t_test_1 add index idx_t_test_1_name (name);
Query OK, 0 rows affected (0.24 sec)
Records: 0  Duplicates: 0  Warnings: 0[root@localhost] 17:54:52 [testdb1]>begin;
Query OK, 0 rows affected (0.00 sec)[root@localhost] 17:54:55 [testdb1]>insert into t_test_2 select * from t_test_1 where name like 'trest';
Query OK, 1 row affected (0.00 sec)
Records: 1  Duplicates: 0  Warnings: 0

重新获取innodb的lock详细信息

TRANSACTIONS
------------
Trx id counter 182565
Purge done for trx's n:o < 182565 undo n:o < 0 state: running but idle
History list length 0
LIST OF TRANSACTIONS FOR EACH SESSION:
---TRANSACTION 421524582451936, not started
0 lock struct(s), heap size 1136, 0 row lock(s)
---TRANSACTION 182560, ACTIVE 3 sec
3 lock struct(s), heap size 1136, 2 row lock(s), undo log entries 1
MySQL thread id 11, OS thread handle 140049254979328, query id 105 localhost root
TABLE LOCK table `testdb1`.`t_test_1` trx id 182560 lock mode IS
RECORD LOCKS space id 97 page no 4 n bits 72 index idx_t_test_1_name of table `testdb1`.`t_test_1` trx id 182560 lock mode S
Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 00: len 8; hex 73757072656d756d; asc supremum;;Record lock, heap no 6 PHYSICAL RECORD: n_fields 2; compact format; info bits 00: len 10; hex 74726573742020202020; asc trest     ;;1: len 4; hex 80000001; asc     ;;TABLE LOCK table `testdb1`.`t_test_2` trx id 182560 lock mode IX

看到没有,在这里,现在只有一个Record lock,不再是锁全表了。

深入研究insert into select锁表故障(下)

“深入研究insert into select语句锁表故障(上)”中,已经详细介绍了如何模拟insert into select锁表复盘,以及获取详细的Lock信息,和解决方案。

隔离级别
分析一个故障,一定要看数据库的隔离级别,在不同的隔离级别下,会有不一样的结果。

RR隔离级别
获取数据库的隔离级别

[root@localhost] 18:11:29 [testdb1]>show variables like '%iso%';
+-----------------------+-----------------+
| Variable_name         | Value           |
+-----------------------+-----------------+
| transaction_isolation | REPEATABLE-READ |
| tx_isolation          | REPEATABLE-READ |
+-----------------------+-----------------+
2 rows in set (0.00 sec)`

模拟insert into select锁表

[root@localhost] 17:54:52 [testdb1]>begin;
Query OK, 0 rows affected (0.00 sec)[root@localhost] 17:54:55 [testdb1]>insert into t_test_2 select * from t_test_1 where name like 'trest';
Query OK, 1 row affected (0.00 sec)
Records: 1  Duplicates: 0  Warnings: 0

获取lock信息

TRANSACTIONS
------------
Trx id counter 182565
Purge done for trx's n:o < 182565 undo n:o < 0 state: running but idle
History list length 0
LIST OF TRANSACTIONS FOR EACH SESSION:
---TRANSACTION 421524582451936, not started
0 lock struct(s), heap size 1136, 0 row lock(s)
---TRANSACTION 182560, ACTIVE 3 sec
3 lock struct(s), heap size 1136, 2 row lock(s), undo log entries 1
MySQL thread id 11, OS thread handle 140049254979328, query id 105 localhost root
TABLE LOCK table `testdb1`.`t_test_1` trx id 182560 lock mode IS
RECORD LOCKS space id 97 page no 4 n bits 72 index idx_t_test_1_name of table `testdb1`.`t_test_1` trx id 182560 lock mode S
Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 00: len 8; hex 73757072656d756d; asc supremum;;Record lock, heap no 6 PHYSICAL RECORD: n_fields 2; compact format; info bits 00: len 10; hex 74726573742020202020; asc trest     ;;1: len 4; hex 80000001; asc     ;;TABLE LOCK table `testdb1`.`t_test_2` trx id 182560 lock mode IX

RC隔离级别
获取数据库的隔离级别

[root@localhost] 18:14:58 [(none)]>show variables like '%iso%';
+-----------------------+----------------+
| Variable_name         | Value          |
+-----------------------+----------------+
| transaction_isolation | READ-COMMITTED |
| tx_isolation          | READ-COMMITTED |
+-----------------------+----------------+
2 rows in set (0.00 sec)

获取lock信息

[root@localhost] 18:15:39 [(none)]>show engine innodb status\G;
TRANSACTIONS
------------
Trx id counter 183051
Purge done for trx's n:o < 183046 undo n:o < 0 state: running but idle
History list length 0
LIST OF TRANSACTIONS FOR EACH SESSION:
---TRANSACTION 421137823890144, not started
0 lock struct(s), heap size 1136, 0 row lock(s)
---TRANSACTION 183050, ACTIVE 5 sec
1 lock struct(s), heap size 1136, 0 row lock(s), undo log entries 1
MySQL thread id 5, OS thread handle 139662496147200, query id 17 localhost root
TABLE LOCK table `testdb1`.`t_test_2` trx id 183050 lock mode IX

看到没有,在隔离级别RC下,insert into t_test_2 select * from t_test_1 where name like 'trest’语句,在t_test_1表上没有任何的lock产生。

建议

在生产使用insert into t_test_2 select * from t_test_1 where name like 'trest’语句时,有以下2个建议
建议一:建议mysql数据库隔离级别使用RC
建议二:select表的查询条件字段,建议创建索引

参考链接:

深入研究insert into select语句锁表故障(上) : https://mp.weixin.qq.com/s/PL0pIIfzYKJWq6qg7A1Hzw

深入研究insert into select锁表故障(下) : https://mp.weixin.qq.com/s/XpDPa8QlnqnpEoif2G40EQ

insert into select语句锁表故障相关推荐

  1. 【MySQL】MySQL Insert into select 大量锁表导致无法插入

    1.概述 原文:因用了Insert into select语句,同事被开除了! Insert into select 请慎用,同事因为使用了 Insert into select 语句引发了重大生产事 ...

  2. MySQL的insert into select 引发锁表

    上周五HaC我要上线,有一个脚本需要执行,执行前需要备份一个表. 运维大佬:"这个表的备份为什么要这么久,,??" 1秒过去了--2秒过去了-- 期间运营反馈系统出现大量订单超时情 ...

  3. delete 会不会锁表_MySQL的insert into select 引发锁表

    上周五HaC我要上线,有一个脚本需要执行,执行前需要备份一个表. 运维大佬:"这个表的备份为什么要这么久,,??" 1秒过去了--2秒过去了-- 期间运营反馈系统出现大量订单超时情 ...

  4. 查询很慢会导致锁表吗_MySQL的insert into select 引发锁表

    上周五HaC我要上线,有一个脚本需要执行,执行前需要备份一个表. 运维大佬:"这个表的备份为什么要这么久,,??" 1秒过去了--2秒过去了-- 期间运营反馈系统出现大量订单超时情 ...

  5. SELECT INTO 和 INSERT INTO SELECT 两种表复制语句

    SELECT INTO 和 INSERT INTO SELECT 两种表复制语句 Insert是T-sql中常用语句,Insert INTO table(field1,field2,...) valu ...

  6. SELECT INTO 和 INSERT INTO SELECT 两种表复制语句详解(SQL数据库和Oracle数据库的区别)...

    我们经常会遇到需要表复制的情况,如将一个table1的数据的部分字段复制到table2中,或者将整个table1复制到table2中,这时候我们就要使用SELECT INTO 和 INSERT INT ...

  7. SELECT INTO 和 INSERT INTO SELECT 两种表复制语句 (以后在写SQL时,要有这种思想!!!)

    今天天在工作中看到了一个业务要求,具体要求是这样的,根据一堆条件从一个表中查询出符合条件的ID,然后把这个ID插入到一张表中. 技术是使用iBaits和数据库连接,当时我的第一反应是两次查询,先得到I ...

  8. oracle select into 多个,Oracle SELECT INTO 和 INSERT INTO SELECT 两种表复制语句详解

    在Oracle中select into from不可以使用,用create tableselect代替该功能!!!在Sql Server中可以正常使用.1.INSERT INTOSELECT语句 语句 ...

  9. SQL Server 中 SELECT INTO 和 INSERT INTO SELECT语句的区别

    SQL Server 中 SELECT INTO 和 INSERT INTO SELECT语句的区别 我们在写存储过程的时候经常会遇到需要将查询到的数据存到一张表里面的情况,如将一个table1的数据 ...

最新文章

  1. [Go]在vscode中添加对模板文件tmpl的html语法自动补全的支持
  2. FTL页面常用到的一些方法combobox、combotree、datagrid
  3. 超大规模数据中心容量在四年内翻了一番,中国占比15%
  4. Client向Server send数据,返回WSAEWOULDBLOCK错误
  5. oracle两列合并成一列_POWER QUERY--一个工作簿内的多张工作表合并汇总
  6. 2021年三大顶会时间序列论文代码整理
  7. 域嵌套太深_pyspark如何修改嵌套结构域
  8. python查询最高分_精通 Oracle+Python,第 1 部分:查询最佳应践
  9. DNS域传输漏洞利用总结
  10. 求你了,别再说Java对象都是在堆内存上分配空间的了!
  11. java集合合并_【Java必修课】各种集合类的合并(数组、List、Set、Map)
  12. el-option传两个值_真正的释家或佛学研究者、爱好者必读文献——南朝梁·释慧皎《高僧传》...
  13. 快速排序—三路快排 vs 双基准
  14. NullableTypes for .NET
  15. You need libtool version 1.5.14 or newer to build
  16. java 调用oracle函数_java – 用Spring的SimpleJdbcCall来调用Oracle函数
  17. SQL 插入时直接插入当前时间
  18. 解决9341系列LCD,使用杜邦线等连接线,造成白屏问题
  19. python --opencv图像处理轮廓(寻找轮廓、绘制轮廓)详解
  20. Unity中的3D数学—02向量与矩阵

热门文章

  1. python38环境变量的配置_Windows下python环境变量配置
  2. 南开100题计算机三级网络技术,计算机三级网络技术上机南开100题T46-50 -.pdf
  3. [TensorRT] INTERNAL ERROR: Assertion failed: mem = nullpt
  4. win7日历加入农历_还是农历更亲切,春节制作一个带农历的日历,欢欢喜喜过新年...
  5. 你需知道的MFI:mean, Median,Mode及Geometric Mean 之比较
  6. 11gR2 Grid Infrastructure Installation prerequisites On LINUX
  7. Android仿人人客户端(v5.7.1)——应用主界面之左侧面板UI实现
  8. HTML5开源RPG游戏引擎lufylegendRPG 0.1发布
  9. path的图片下拉效果
  10. Fixchart图表组件——介绍