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!