SQL Server 2016對INSERT INTO XXXX SELECT語句進行了優化,在某些情況下可以觸發數據的並行插入,但是要求兼容模式是130(SQL Server 2016)以及在插入的時候加表鎖(WITH(TABLOCK))。那是不是大部分情況都能觸發,並不是。除了上面提到的兩點必要條件,還有苛刻的限制條件:1)不能有額外的索引,目標表只能是堆或者聚集索引的存儲模式;2)表不能有SEQUENCE字段或者IDENTITY字段;當然這兩點是基於目標表是B樹或者堆存儲結構的表。SQL Server 2016對ColumnStored Index做了大量優化,加入Batch Mode,也就是數據在插入到列存儲索引的時候就是並行插入的。
首先第一種情況是從一張表select insert into到另外一張表。這種情況是可以觸發並行插入的。但是和具體有多少行有關系。整個測試中我測試了5W、10W、100W行。結果發現還要和執行計划扯上關系。如果第一次插入是10W行或者100W行都觸發了並行,但是第二次改成5W行則沒有並行,當插入5W行后執行計划被緩存了,再插入100W行也不會觸發並行。只有重編譯或者重建表索引導致查詢語句下次重編譯才會觸發並行(插入100W行)。而觸發並行的臨界點,在測試例子中是10W行。第二種情況是多張表連接后插入數據。這個例子里面還要分開來看。就是目標表是啟用了兼容模式是130,而且也加了表鎖,但是源表的數據庫可能不是SQL Server 2016的兼容模式,是否對結果造成影響。按道理應該是不會,因為並行是對數據插入的並行,而不影響連接表的庫的來源或者兼容模式是什么。但是測試下來發現,即便我插入了100W行也沒能觸發並行。
情況1腳本
CREATE TABLE [dbo].[Table_1]( [col1] [int] NULL, [col2] [nvarchar](50) NULL, [col3] [datetime] NULL ) ON [PRIMARY] GO CREATE TABLE [dbo].[Table_2]( [col1] [int] NULL, [col2] [nvarchar](50) NULL, [col3] [datetime] NULL ) ON [PRIMARY] GO insert [dbo].[Table_1]WITH(TABLOCK) select TOP 1000000 CHECKSUM(NEWID()), REPLICATE('a',50), getdate() from sys.columns a, sys.columns b insert [dbo].[Table_2]WITH(TABLOCK) select * from [dbo].[Table_1] OPTION (RECOMPILE) TRUNCATE TABLE [dbo].[Table_1] TRUNCATE TABLE [dbo].[Table_2]
參考:
SQLSweet16!, Episode 3: Parallel INSERT … SELECT
Real World Parallel INSERT…SELECT: What else you need to know!