Sql-Server
高效的 INSERT INTO 帶有聚集索引的表
我有一個 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 BY
以SELECT
最小化頁面拆分和隨後的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
是否低於將排序添加到計劃的門檻值。然而,正如下面評論中所指出的,這確實意味著插入將無法利用最少的日誌記錄。