一次性事務和CTE插入數據的比較

玩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萬條記錄的插入,速度仍是挺快的。(若是沒有加顯式事務,要多久才能完成呢?有興趣的朋友能夠試下Be right backspa

 

下面是使用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

 

wKiom1bmLzaBgknQAACHvKSvvgQ184.jpg

figure-1

 

個人機器上生成了1億1多千萬條記錄。

相關文章
相關標籤/搜索