Wie in den anderen Antworten bereits angegeben, kann SQL Server explizit sicherstellen, dass die Zeilen vor dem in Gruppen zusammengefassten Index in der angegebenen Reihenfolge sortiert werden insert
.
Dies hängt davon ab, ob für den gruppierten Indexoperator im Plan die DMLRequestSort
Eigenschaft festgelegt wurde (was wiederum von der geschätzten Anzahl der eingefügten Zeilen abhängt).
Wenn Sie feststellen , dass SQL Server dies wird unterschätzt welchen Grund auch immer Sie das Hinzufügen einer expliziten Nutzen ziehen kann , ORDER BY
um die SELECT
Abfrage - Seite Splits zu minimieren und die daraus resultierende Fragmentierung der INSERT
Operation
Beispiel:
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')
;
Zeigt, dass T
massiv fragmentiert ist
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
Aber für die T2
Fragmentierung ist minimal
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
Umgekehrt möchten Sie SQL Server manchmal dazu zwingen, die Zeilenanzahl zu unterschätzen, wenn Sie wissen, dass die Daten bereits vorsortiert sind und eine unnötige Sortierung vermeiden möchten. Ein bemerkenswertes Beispiel ist das Einfügen einer großen Anzahl von Zeilen in eine Tabelle mit einem newsequentialid
Clustered-Indexschlüssel. In Versionen von SQL Server vor Denali fügt SQL Server einen unnötigen und möglicherweise teuren Sortiervorgang hinzu . Dies kann vermieden werden durch
DECLARE @var INT =2147483647
INSERT INTO Foo
SELECT TOP (@var) *
FROM Bar
SQL Server schätzt dann, dass 100 Zeilen eingefügt werden, unabhängig von der Größe, Bar
die unter dem Schwellenwert liegt, ab dem dem Plan eine Sortierung hinzugefügt wird. Wie in den Kommentaren unten ausgeführt, bedeutet dies jedoch, dass die Beilage die minimale Protokollierung leider nicht nutzen kann.
Wenn der Optimierer entscheidet, dass es effizienter ist, die Daten vor dem Einfügen zu sortieren, geschieht dies irgendwo vor dem Einfügeoperator. Wenn Sie eine Sortierung als Teil Ihrer Abfrage einführen, sollte das Optimierungsprogramm erkennen, dass die Daten bereits sortiert sind, und dies erneut auslassen. Beachten Sie, dass der gewählte Ausführungsplan von Ausführung zu Ausführung variieren kann, abhängig von der Anzahl der Zeilen, die aus Ihrer Staging-Tabelle eingefügt wurden.
Wenn Sie Ausführungspläne des Prozesses mit und ohne explizite Sortierung erfassen können, hängen Sie sie zur Kommentierung an Ihre Frage an.
Bearbeiten: 2011-10-28 17:00
@ Gonsalus Antwort scheint zu zeigen, dass immer eine Sortieroperation stattfindet, dies ist jedoch nicht der Fall. Demo-Skripte erforderlich!
Da die Skripte ziemlich umfangreich wurden, habe ich sie nach Gist verschoben . Um das Experimentieren zu vereinfachen, verwenden die Skripte den SQLCMD-Modus. Tests laufen auf 2K5SP3, Dual Core, 8GB.
Die Einfügetests decken drei Szenarien ab:
Erster Lauf, Einfügen von 25 Zeilen.
Alle drei Ausführungspläne sind gleich, es wird nirgendwo im Plan eine Sortierung vorgenommen, und der Clustered-Index-Scan lautet "ordered = false".
Zweiter Durchgang, Einfügen von 26 Reihen.
Diesmal sind die Pläne unterschiedlich.
Es gibt also einen Wendepunkt, an dem der Optimierer eine Sortierung für notwendig hält. Wie @MartinSmith zeigt, scheint dies auf den geschätzten einzufügenden Zeilen zu beruhen. Auf meinem Prüfstand ist für 25 keine Sortierung erforderlich, für 26 (2K5SP3, Dual Core, 8 GB).
Das Skript SQLCMD enthält Variablen, mit denen die Größe der Zeilen in der Tabelle geändert werden kann (Änderung der Seitendichte) und die Anzahl der Zeilen in dbo.MyTable vor den zusätzlichen Einfügungen. Beides hat nach meinem Test keinen Einfluss auf den Wendepunkt.
Wenn Leser dazu neigen, führen Sie bitte die Skripte aus und fügen Sie Ihren Tipp als Kommentar hinzu. Interessiert zu hören, ob es sich um unterschiedliche Prüfstände und / oder Versionen handelt.
Edit: 2011-10-28 20:15
Wiederholte Tests auf dem gleichen Rig, aber mit 2K8R2. Diesmal beträgt der Wendepunkt 251 Zeilen. Auch hier hat das Ändern der Seitendichte und der Anzahl der vorhandenen Zeilen keine Auswirkung.
quelle
Die
ORDER BY
Klausel in derSELECT
Anweisung ist überflüssig.Es ist redundant, da die einzufügenden Zeilen, falls sie sortiert werden müssen , ohnehin sortiert werden.
Lassen Sie uns einen Testfall erstellen.
Lassen Sie uns die Textanzeige der tatsächlichen Abfragepläne aktivieren, damit wir sehen können, welche Aufgaben vom Abfrageprozessor ausgeführt werden.
Lassen Sie uns nun
INSERT
2K-Zeilen ohneORDER BY
Klausel in die Tabelle einfügen.Der tatsächliche Ausführungsplan für diese Abfrage lautet wie folgt.
Wie Sie sehen, gibt es einen Sortieroperator, bevor das eigentliche INSERT auftritt.
Löschen wir nun die Tabelle und
INSERT
fügen 2k Zeilen mit derORDER BY
Klausel in die Tabelle ein .Der tatsächliche Ausführungsplan für diese Abfrage lautet wie folgt.
Beachten Sie, dass dies derselbe Ausführungsplan ist, der für die
INSERT
Anweisung ohne dieORDER BY
Klausel verwendet wurde.Nun ist die
Sort
Operation nicht immer erforderlich, wie Mark Smith in einer anderen Antwort gezeigt hat (wenn die Anzahl der einzufügenden Zeilen niedrig ist), aber dieORDER BY
Klausel ist in diesem Fall immer noch redundant, da selbst mit einer expliziten OperationORDER BY
keineSort
Operation generiert wird durch den Abfrageprozessor.Sie können eine
INSERT
Anweisung in eine Tabelle mit einem Clustered-Index optimieren , indem Sie eine minimal protokollierte Anweisung verwenden.INSERT
Dies ist jedoch für diese Frage nicht relevant.Aktualisiert am 2011-11-02: Wie Mark Smith gezeigt hat, muss
INSERT
eine Tabelle mit einem Clustered-Index möglicherweise nicht immer sortiert werden - dieORDER BY
Klausel ist jedoch auch in diesem Fall redundant.quelle