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)
復制代碼


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM