Sql-Server

高效的 INSERT INTO 帶有聚集索引的表

  • November 13, 2011

我有一個 SQL 語句,它將行插入到一個表中,該表在 TRACKING_NUMBER 列上有一個聚集索引。

例如:

INSERT INTO TABL_NAME (TRACKING_NUMBER, COLB, COLC) 
SELECT TRACKING_NUMBER, COL_B, COL_C 
FROM STAGING_TABLE

我的問題是 - 在 SELECT 語句中為聚集索引列使用 ORDER BY 子句是否有幫助,或者 ORDER BY 子句所需的額外排序是否會否定所獲得的任何收益?

由於其他答案已經表明 SQL Server 可能會或可能不會明確確保行在insert.

這取決於計劃中的聚集索引運算符是否具有DMLRequestSort屬性集(這又取決於估計的插入行數)。

如果您發現 SQL Server 出於某種原因低估了這一點,您可能會受益於向查詢添加顯式ORDER BYSELECT最小化頁面拆分和隨後的INSERT操作碎片

例子:

use tempdb;

GO

CREATE TABLE T(N INT PRIMARY KEY,Filler char(2000))

CREATE TABLE T2(N INT PRIMARY KEY,Filler char(2000))

GO

DECLARE @T TABLE (U UNIQUEIDENTIFIER PRIMARY KEY DEFAULT NEWID(),N int)

INSERT INTO @T(N)
SELECT number 
FROM master..spt_values
WHERE type = 'P' AND number BETWEEN 0 AND 499

/*Estimated row count wrong as inserting from table variable*/
INSERT INTO T(N)
SELECT T1.N*1000 + T2.N
FROM @T T1, @T T2

/*Same operation using explicit sort*/    
INSERT INTO T2(N)
SELECT T1.N*1000 + T2.N
FROM @T T1, @T T2
ORDER BY T1.N*1000 + T2.N


SELECT avg_fragmentation_in_percent,
      fragment_count,
      page_count,
      avg_page_space_used_in_percent,
      record_count
FROM   sys.dm_db_index_physical_stats(2, OBJECT_ID('T'), NULL, NULL, 'DETAILED')
;  


SELECT avg_fragmentation_in_percent,
      fragment_count,
      page_count,
      avg_page_space_used_in_percent,
      record_count
FROM   sys.dm_db_index_physical_stats(2, OBJECT_ID('T2'), NULL, NULL, 'DETAILED')
;  

顯示T非常分散的節目

avg_fragmentation_in_percent fragment_count       page_count           avg_page_space_used_in_percent record_count
---------------------------- -------------------- -------------------- ------------------------------ --------------------
99.3116118225536             92535                92535                67.1668272794663               250000
99.5                         200                  200                  74.2868173956017               92535
0                            1                    1                    32.0978502594514               200

但是對於T2碎片是最小的

avg_fragmentation_in_percent fragment_count       page_count           avg_page_space_used_in_percent record_count
---------------------------- -------------------- -------------------- ------------------------------ --------------------
0.376                        262                  62500                99.456387447492                250000
2.1551724137931              232                  232                  43.2438349394613               62500
0                            1                    1                    37.2374598468001               232

相反,當您知道數據已經預先排序並希望避免不必要的排序時,有時您可能希望強制 SQL Server 低估行數。newsequentialid一個值得注意的範例是在使用聚集索引鍵將大量行插入到表中時。在 Denali SQL Server 之前的 SQL Server 版本中,SQL Server 增加了一個不必要且可能代價高昂的排序操作。這可以通過

DECLARE @var INT =2147483647

INSERT INTO Foo
SELECT TOP (@var) *
FROM Bar

然後 SQL Server 將估計將插入 100 行,無論其大小Bar是否低於將排序添加到計劃的門檻值。然而,正如下面評論中所指出的,這確實意味著插入將無法利用最少的日誌記錄。

引用自:https://dba.stackexchange.com/questions/7350