玩SQL Server的同窗,有时可能要构造一些数据来作测试数据,像下面这样:sql
IF OBJECT_ID(N'T14') IS NOT NULL BEGIN DROP TABLE T14 END GO CREATE TABLE T14 (t14_id INT) GO DECLARE @i INT = 1 WHILE @i <= 1000 BEGIN INSERT INTO T14 (t14_id) SELECT @i SET @i = @i + 1 END GO
code-1ide
这里存在一个问题,每运行一次insert至关于commit了一次事务,数据量小的还不会出现问题,若是把要插入100万,200万,1000万 甚至更多的数据呢?既然insert语句是隐式commit的,在这个循环外面加一个显式的事务,便可显著提升插入的性能。另外一种方法就是使用CTE也可 以一次把数据插入到表中,从而提升性能。如今就这两种方法插入数据的性能来作一个比较。没有结果以前,猜猜哪一种速度更快?或者二者差很少?性能
首先是加事务,插入100万条记录:测试
IF OBJECT_ID(N'T14') IS NOT NULL BEGIN DROP TABLE T14 END GO CREATE TABLE T14 (t14_id INT) GO DBCC FREESESSIONCACHE DBCC DROPCLEANBUFFERS GO SET NOCOUNT ON; BEGIN TRAN DECLARE @i INT = 1 WHILE @i <= 1000000 BEGIN INSERT INTO T14 (t14_id) SELECT @i SET @i = @i + 1 END COMMIT TRAN; SET NOCOUNT OFF; GO
code-2大数据
个人机器上测试屡次,取平均值,大概使用了22秒便可完成100万条记录的插入,速度仍是挺快的。(若是没有加显式事务,要多久才能完成呢?有兴趣的朋友能够试下)spa
下面是使用CTE:日志
CREATE TABLE T15 (t15_id INT) GO DBCC FREESESSIONCACHE DBCC DROPCLEANBUFFERS GO WITH CTE1 AS ( SELECT a.[object_id] FROM master.sys.all_objects AS a CROSS JOIN master.sys.all_objects AS b ) ,CTE2 AS ( SELECT ROW_NUMBER() OVER (ORDER BY [object_id]) as row_no FROM CTE1 ) INSERT INTO T15 (t15_id) SELECT row_no FROM CTE2 WHERE row_no <= 1000000 GO
code-3code
也是测试屡次取平均值,居然是5秒左右就完成,大大出乎个人意料!如今改成插入1000万条记录,看结果如何。前者只需把code-2中的1000000修改成10000000,再运行便可。后者因为CTE1的记录数不够,须要UNION ALL两次,代码以下:blog
CREATE TABLE T15 (t15_id INT) GO DBCC FREESESSIONCACHE DBCC DROPCLEANBUFFERS GO WITH CTE1 AS ( SELECT a.[object_id] FROM master.sys.all_objects AS a CROSS JOIN master.sys.all_objects AS b ) ,CTE2 AS ( SELECT ROW_NUMBER() OVER (ORDER BY [object_id]) as row_no FROM CTE1 ) INSERT INTO T15 (t15_id) SELECT row_no FROM CTE2 WHERE row_no <= 1000000 GO
code-4索引
测试结果:加事务的插入大概须要3分多钟,而CTE则不超过1分半钟的时间就完成了。看来仍是CTE更高效啊!在测试过程当中,发现内存的使用量很少,但CPU的使用有较明显的提升。此外,插入大数据到表中,有无索引和日志恢复模式也会影响插入的性能。
补充一下CTE1中记录数的生成。若是只须要100万的数据量,只须要master.sys.databases表CROSS JOIN本身一次就能够了,或者找两张表CROSS JOIN后数据更接近的所需就更好了,不够的能够UNIONL ALL几回。那若是须要1000万或更大的记录数,能够在此基础上再CROSS JOIN一次一张小表,好比:
SELECT a.[object_id] FROM master.sys.all_objects AS a CROSS JOIN master.sys.all_objects AS b CROSS JOIN master.sys.databases AS c ) SELECT COUNT(*) AS counts,LEN(COUNT(*)) AS counts_length FROM CTE3 GO
code-5
figure-1
个人机器上生成了1亿1多千万条记录。