摘要:

      一直以为"insert into tb select * from tbx" 这样的导入操作是会把tbx表给锁住的,在锁期间是不允许任何操作(保证一致性)。看完这篇写的之后,发现其实我错了一半。tbx表是会被锁住,但这个锁有2种情况,现在逐一进行分析:

分析

环境:

root@127.0.0.1 : test 02:10:40>select @@global.tx_isolation,@@session.tx_isolation;
+-----------------------+------------------------+
| @@global.tx_isolation | @@session.tx_isolation |
+-----------------------+------------------------+
| REPEATABLE-READ       | REPEATABLE-READ        |
+-----------------------+------------------------+
1 row in set (0.00 sec)

root@127.0.0.1 : test 02:10:50>select @@version;
+------------+
| @@version  |
+------------+
| 5.6.10-log |
+------------+
1 row in set (0.00 sec)

1:按照主键排序插入的情况

直接插入,不加排序字段(默认):

session1:执行操作,表只有5W条记录
root@127.0.0.1 : test 02:10:51>insert into uu select * from user;

session2:查看操作锁的情况(锁的行数)
root@127.0.0.1 : (none) 02:13:30>pager grep "lock(s)"
PAGER set to 'grep "lock(s)"'root@127.0.0.1 : (none) 02:18:08>show engine innodb status; #被锁的行数逐步增加
274 lock struct(s), heap size 31160, 17746 row lock(s), undo log entries 17474
root@127.0.0.1 : (none) 02:18:16>show engine innodb status;
500 lock struct(s), heap size 63928, 32572 row lock(s), undo log entries 32074
root@127.0.0.1 : (none) 02:18:17>show engine innodb status;
676 lock struct(s), heap size 80312, 44308 row lock(s), undo log entries 43635

用主键升序插入:

  情况和1一样。即默认的"select * from tb" 和 "select * from tb order id(PK) ASC " 是一样的情况。

用主键倒序插入:

  情况和1一样。即默认的"select * from tb" 和 "select * from tb order id(PK) DESC" 是一样的情况,这里说的一样是锁方式一样(都是逐步,只是顺序不一样)。

从上面可知:通过主键排序或则不加排序字段的导入操作"insert into tb select * from tbx",是会锁tbx表,但他的锁是逐步地锁定已经扫描过的记录。

2:按照非主键排序插入的情况

session1:执行操作
root@127.0.0.1 : test 02:33:00>insert into uu select * from user order by createTime ;

session2:查看操作锁的情况(行数)
root@127.0.0.1 : (none) 02:27:29>pager grep "lock(s)"
root@127.0.0.1 : (none) 02:27:54>show engine innodb status;  #被锁的行数一样,不变(整张表)
773 lock struct(s), heap size 80312, 50771 row lock(s), undo log entries 1843

root@127.0.0.1 : (none) 02:33:19>show engine innodb status; 773 lock struct(s), heap size 80312, 50771 row lock(s), undo log entries 17680

root@127.0.0.1 : (none) 02:33:20>show engine innodb status; 773 lock struct(s), heap size 80312, 50771 row lock(s), undo log entries 22260

root@127.0.0.1 : (none) 02:33:21>show engine innodb status; 773 lock struct(s), heap size 80312, 50771 row lock(s), undo log entries 28960

从上面可知:通过非主键排序的导入操作"insert into tb select * from tbx",是会锁tbx表,但他的锁是一开始就会锁定整张表。

总之,"insert into tb select * from tbx" 的导入操作是会锁定原表,但是锁是有2种情况:“逐步锁”,“全锁”。



验证:

针对1的情况:逐步锁定扫描过的记录,那操作未扫描的数据会怎么样?

session1:执行操作
root@127.0.0.1 : test 02:55:27>insert into uu select * from user;
Query OK, 49998 rows affected (9.06 sec)

session2:测试操作锁的情况
root@127.0.0.1 : test 02:54:49>delete from user where id = 33333;update user set username='TEST' where id = 44444;insert into user(id,username,company) values(1000,'ASD','ABCASDA');
Query OK, 0 rows affected (0.00 sec) #可以删除未扫描(锁)的数据(id=33333)

Query OK, 0 rows affected (0.00 sec)
Rows matched: 1  Changed: 0  Warnings: 0 #可以更新为扫描(锁)的数据(id=44444)

Query OK, 1 row affected (8.09 sec)#插入(更新,删除)操作被锁了,因为该记录已经被扫描到(id=1000)

session3:查看操作的锁情况:
root@127.0.0.1 : (none) 02:55:33>show engine innodb status;
LOCK WAIT 2 lock struct(s), heap size 376, 1 row lock(s)
272 lock struct(s), heap size 31160, 17574 row lock(s), undo log entries 17305
1 row in set (0.09 sec)

root@127.0.0.1 : (none) 02:55:35>show engine innodb status;
LOCK WAIT 2 lock struct(s), heap size 376, 1 row lock(s)
448 lock struct(s), heap size 47544, 29109 row lock(s), undo log entries 28664
1 row in set (0.01 sec)

root@127.0.0.1 : (none) 02:55:37>show engine innodb status;
LOCK WAIT 2 lock struct(s), heap size 376, 1 row lock(s)
612 lock struct(s), heap size 63928, 40034 row lock(s), undo log entries 39425
1 row in set (0.00 sec)

root@127.0.0.1 : (none) 02:55:39>show engine innodb status;
1 row in set (0.01 sec)

从上面看出,刚好说明了1的情况:逐步的锁定已经扫描过的记录。

默认、主键升序的select :从第一行开始扫描到最后,即第一行开始锁直到最后。

主键倒序select             :从最后一行开始扫描到最前,即最后一行开始锁直到第一行。

针对2的情况:锁定整张表,那就是表锁;不能进行任何操作,直到锁释放了?

session1:执行操作
root@127.0.0.1 : test 03:23:06>insert into uu select * from user order by company;
Query OK, 49994 rows affected (13.70 sec)

session2:测试操作锁的情况
root@127.0.0.1 : test 03:22:44>delete from user where id = 33337;update user set username='TESAAST' where id = 44443;insert into user(id,username,company) values(1000,'ASD','ABCASDA');
Query OK, 1 row affected (9.58 sec)  #直接被锁住了,等待session1释放了。

Query OK, 0 rows affected (0.00 sec)
Rows matched: 1  Changed: 0  Warnings: 0 #同上

Query OK, 1 row affected (0.00 sec) #同上

session3:查看操作的锁情况:
root@127.0.0.1 : (none) 03:22:45>pager grep "lock(s)"
PAGER set to 'grep "lock(s)"'
root@127.0.0.1 : (none) 03:23:20>show engine innodb status;
773 lock struct(s), heap size 80312, 50765 row lock(s), undo log entries 4433
1 row in set (0.02 sec)

root@127.0.0.1 : (none) 03:23:28>show engine innodb status;
LOCK WAIT 2 lock struct(s), heap size 376, 1 row lock(s)
773 lock struct(s), heap size 80312, 50765 row lock(s), undo log entries 25383
1 row in set (0.06 sec)

root@127.0.0.1 : (none) 03:23:32>show engine innodb status;
LOCK WAIT 2 lock struct(s), heap size 376, 1 row lock(s)
773 lock struct(s), heap size 80312, 50765 row lock(s), undo log entries 42464
1 row in set (0.01 sec)

从上面看出,刚好说明了2的情况:一开始就会锁定整张表的记录,不能进行任何操作,直到锁释放了。



总结:

类似"insert into tb select * from tbx" 的操作,最好确保tbx表不被做dml操作,不然很可能出现锁等待的情况。另:通过设置隔离级别:read committed & ROW(binlog_format)可以让dml和该语句并发操作。

session1:执行操作
root@127.0.0.1 : test 04:05:08>insert into uu select * from user order by company;
Query OK, 49990 rows affected (14.09 sec)

session2:测试操作锁的情况
root@127.0.0.1 : test 04:04:57>delete from user where id = 33318;update user set username='TESAAeST' where id = 44423;insert into user(id,username,company) values(1000,'ASD','ABCASDA');
Query OK, 0 rows affected (0.00 sec)

Query OK, 0 rows affected (0.00 sec)
Rows matched: 1  Changed: 0  Warnings: 0

Query OK, 1 row affected (0.00 sec)

session3:查看操作的锁情况:
root@127.0.0.1 : (none) 03:22:45>pager grep "lock(s)"
PAGER set to 'grep "lock(s)"'
root@127.0.0.1 : test 04:05:23>show engine innodb status;
1 lock struct(s), heap size 376, 0 row lock(s), undo log entries 6256
1 row in set (0.05 sec)

root@127.0.0.1 : test 04:05:28>show engine innodb status;
1 lock struct(s), heap size 376, 0 row lock(s), undo log entries 32958
1 row in set (0.01 sec)

root@127.0.0.1 : test 04:05:35>show engine innodb status;
1 lock struct(s), heap size 376, 0 row lock(s), undo log entries 33784
1 row in set (0.00 sec)

root@127.0.0.1 : test 04:05:36>show engine innodb status;
1 lock struct(s), heap size 376, 0 row lock(s), undo log entries 34789
1 row in set (0.00 sec)

参考:

http://www.cnblogs.com/zhoujinyi/archive/2013/04/28/3049382.html

http://blog.csdn.net/muzizhuben/article/details/46533799

http://blog.chinaunix.net/uid-9950859-id-181376.html

关于MySQL insert into ... select 的锁情况的更多相关文章

  1. 实战演示疑惑 mysql insert到底加什么锁

    innodb的事务隔离级别是可重复读级别且innodb_locks_unsafe_for_binlog禁用,也就是说允许next-key lock 实验来自网上. ( 如果你没有演示出来,请check ...

  2. insert into select * from 锁表

    mysql[192.168.11.187] processid[249] root@localhost in db[zjzc] hold transaction time 197 112069858, ...

  3. MYSQL INSERT INTO SELECT 不插入重复数据

    INSERT INTO `b_common_member_count` (uid) SELECT uid FROM `b_common_member` WHERE uid NOT IN (SELECT ...

  4. 【数据库系列】MySql中的select的锁表范围

    由于InnoDB预设的是Row-Level Lock,只有明确指定主键的时候MySql才会执行Row lock,否则MySql将会执行Table Lock. 1.明确指定主键则是行锁 2.明确指定主键 ...

  5. mysql insert into select 语法

    Insert into Table2(field1,field2,...) select value1,value2,... from Table1  这样就对了

  6. MySQL : INSERT INTO SELECT

    INSERT INTO wx_announcement_push ( title, content, STATUS, del_flag, user_login_name ) SELECT '大家好', ...

  7. mysql insert锁机制【转】

    最近再找一些MySQL锁表原因,整理出来一部分sql语句会锁表的,方便查阅,整理的不是很全,都是工作中碰到的,会持续更新 笔者能力有限,如果有不正确的,或者不到位的地方,还请大家指出来,方便你我,方便 ...

  8. 语法:MySQL中INSERT INTO SELECT的使用(转)

    1. 语法介绍      有三张表a.b.c,现在需要从表b和表c中分别查几个字段的值插入到表a中对应的字段.对于这种情况,可以使用如下的语句来实现: INSERT INTO db1_name (fi ...

  9. MySQL复制表-INSERT INTO SELECT

    基础table为: mysql> select * from staff; +----+----------+-------+ | id | name | slary | +----+----- ...

随机推荐

  1. jenkins + pipeline构建自动化部署

    一.引言 Jenkins 2.x的精髓是Pipeline as Code,那为什么要用Pipeline呢?jenkins1.0也能实现自动化构建,但Pipeline能够将以前project中的配置信息 ...

  2. 监控undo空间和临时段的使用情况

    --1.监控undo空间情况 ),) free_space from dba_free_space where tablespace_name='UNDOTBS1' group by tablespa ...

  3. SpringSecurity 进行自定义Token校验

    背景 Spring Security默认使用「用户名/密码」的方式进行登陆校验,并通过cookie的方式存留登陆信息.在一些定制化场景,比如希望单独使用token串进行部分页面的访问权限控制时,默认方 ...

  4. golang 线程与通道

    首先我们来看线程,在golang里面也叫goroutine 在读这篇文章之前,我们需要了解一下并发与并行.golang的线程是一种并发机制,而不是并行.它们之间的区别大家可以上网搜一下,网上有很多的介 ...

  5. 关于云Linux部署tomcat服务器(Maven的多模块war包)

    博主的运行环境: 电脑系统: Linux mint 18 JDK版本: java version "1.8.0_171" Maven版本:  Apache Maven 3.5.3 ...

  6. jboss规则引擎KIE Drools 6.3.0 Final 教程(3)

    在前2部教程中,介绍了如何在本地运行.drools文件以及使用stateless的方法访问远程repository上的规则. KIE Drools还提供了一种叫有状态-stateful的访问方式. 运 ...

  7. 多线程(四) 实现线程范围内模块之间共享数据及线程间数据独立(Map集合)

    多个线程访问共享对象和数据的方式 1.如果每个线程执行的代码相同,可以使用同一个Runnable对象,这个Runnable对象中有那个共享数据,例如,买票系统就可以这么做. 2.如果每个线程执行的代码 ...

  8. C实战:强大的程序调试工具GDB

    C实战:强大的程序调试工具GDB 1.基本调试 这里只列举最最常用的GDB命令. 1.1 启动GDB gdb program:准备调试程序.也可以直接进入gdb,再通过file命令加载. 1.2 添加 ...

  9. android M Launcher之LauncherModel (三)

    通过前两篇的分析,我们已经知道了LauncherModel的初始化及工作流程,如果您还不熟悉的话请看前两篇博文 android M Launcher之LauncherModel (一) android ...

  10. SQL语句容易出现错误的地方-连载

    1.语言问题 修改语言注册表\HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432\ORACLE\KEY_DevSuitHome1中的NLS_LANG修改为AMERICAN_AMER ...