zoukankan      html  css  js  c++  java
  • SELECT INTO 和 INSERT INTO SELECT 两种表复制语句

     Insert是T-sql中常用语句,Insert INTO table(field1,field2,...) values(value1,value2,...)这种形式的在应用程序开发中必不可少。但我们在开发、测试过程中,经常会遇到需要表复制的情况,如将一个table1的数据的部分字段复制到table2中,或者将整个table1复制到table2中,这时候我们就要使用SELECT INTO 和 INSERT INTO SELECT 表复制语句了。

          1.INSERT INTO SELECT语句

          语句形式为:Insert into Table2(field1,field2,...) select value1,value2,... from Table1

          要求目标表Table2必须存在,由于目标表Table2已经存在,所以我们除了插入源表Table1的字段外,还可以插入常量。示例如下:


       --1.创建测试表
        create TABLE Table1
        (
            a varchar(10),
            b varchar(10),
            c varchar(10),
            CONSTRAINT [PK_Table1] PRIMARY KEY CLUSTERED
            (
                a ASC
            )
        ) ON [PRIMARY]

        create TABLE Table2
        (
            a varchar(10),
            c varchar(10),
            d int,
            CONSTRAINT [PK_Table2] PRIMARY KEY CLUSTERED
            (
                a ASC
            )
        ) ON [PRIMARY]
        GO
        --2.创建测试数据
        Insert into Table1 values('赵','asds','90')
        Insert into Table1 values('钱','asds','100')
        Insert into Table1 values('孙','asds','80')
        Insert into Table1 values('李','asds',null)
        GO
        select * from Table2

        --3.INSERT INTO SELECT语句复制表数据
        Insert into Table2(a, c, d) select a,c,5 from Table1
        GO

        --4.显示更新后的结果
        select * from Table2
        GO
        --5.删除测试表
        drop TABLE Table1
        drop TABLE Table2


          2.SELECT INTO FROM语句

          语句形式为:SELECT vale1, value2 into Table2 from Table1

          要求目标表Table2不存在,因为在插入时会自动创建表Table2,并将Table1中指定字段数据复制到Table2中。示例如下:


       --1.创建测试表
        create TABLE Table1
        (
            a varchar(10),
            b varchar(10),
            c varchar(10),
            CONSTRAINT [PK_Table1] PRIMARY KEY CLUSTERED
            (
                a ASC
            )
        ) ON [PRIMARY]
        GO

        --2.创建测试数据
        Insert into Table1 values('赵','asds','90')
        Insert into Table1 values('钱','asds','100')
        Insert into Table1 values('孙','asds','80')
        Insert into Table1 values('李','asds',null)
        GO

        --3.SELECT INTO FROM语句创建表Table2并复制数据
        select a,c INTO Table2 from Table1
        GO

        --4.显示更新后的结果
        select * from Table2
        GO
        --5.删除测试表
        drop TABLE Table1
        drop TABLE Table2

     

    关于MySQL insert into ... select 的锁情况

    摘要:
          一直以为"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)
    复制代码

    如何优化用SQL语句INSERT INTO … SELECT插入数据时锁全表的问题

    1、binlog format 启用Row Based Replication(行复制)模式:

    SET GLOBAL binlog_format = 'ROW';

    如果你想永久的启用这个模式,请修改my.cnf 配置文件:

    [mysqld]
    binlog_format=ROW

    2、在执行你的sql语句前,设置当前会话的隔离级别

    SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
    INSERT INTO t1 SELECT ....;

    如果以上设置不起作用,那么请把隔离级别设置得更宽松,并且设置成全局隔离级别:

    SET GLOBAL TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;

    如果你想永久的启用这个模式,请修改my.cnf 配置文件:

    [mysqld]
    transaction-isolation = READ-UNCOMMITTED

    当然,如果你需要更严格的隔离级别,可以使用READ-COMMITTED代替READ-UNCOMMITTED

     

     

     

    要:
          一直以为"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)
    复制代码
  • 相关阅读:
    桥接模式(从多个角度对实现进行分类)
    单例模式
    组合模式(解决 树形 ,局部与整体关系)
    备忘录模式
    适配器模式
    状态模式
    StartUML建模及生成java实体代码
    JPA删除接口报错 : org.hibernate.LazyInitializationException: failed to lazily initialize a collection, could not initialize proxy
    idea创建的gradle项目没有src目录怎么办?
    idea spring源码 gradle编译失败问题
  • 原文地址:https://www.cnblogs.com/duanxz/p/5208336.html
Copyright © 2011-2022 走看看