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)
    复制代码
  • 相关阅读:
    UVA 10462 Is There A Second Way Left?(次小生成树&Prim&Kruskal)题解
    POJ 1679 The Unique MST (次小生成树)题解
    POJ 2373 Dividing the Path (单调队列优化DP)题解
    BZOJ 2709 迷宫花园
    BZOJ 1270 雷涛的小猫
    BZOJ 2834 回家的路
    BZOJ 2506 calc
    BZOJ 3124 直径
    BZOJ 4416 阶乘字符串
    BZOJ 3930 选数
  • 原文地址:https://www.cnblogs.com/duanxz/p/5208336.html
Copyright © 2011-2022 走看看