SQL Server-Indizes - aufsteigend oder absteigend, welchen Unterschied macht es?

138

Wenn Sie in MS SQL Server einen Index für eine Spalte oder eine Anzahl von Spalten erstellen (ich verwende Version 2005), können Sie festlegen, dass der Index für jede Spalte entweder aufsteigend oder absteigend ist. Es fällt mir schwer zu verstehen, warum diese Wahl überhaupt hier ist. Wäre eine Suche mit binären Sortiertechniken in beiden Fällen nicht genauso schnell? Welchen Unterschied macht es, welche Bestellung ich wähle?

Joshua Carmody
quelle

Antworten:

136

Dies ist vor allem bei der Verwendung mit zusammengesetzten Indizes von Bedeutung:

CREATE INDEX ix_index ON mytable (col1, col2 DESC);

kann verwendet werden für:

SELECT  *
FROM    mytable
ORDER BY
        col1, col2 DESC

oder:

SELECT  *
FROM    mytable
ORDER BY
        col1 DESC, col2

, aber nicht für:

SELECT  *
FROM    mytable
ORDER BY
        col1, col2

Ein Index für eine einzelne Spalte kann auf beide Arten effizient zum Sortieren verwendet werden.

Weitere Informationen finden Sie im Artikel in meinem Blog:

Aktualisieren:

Tatsächlich kann dies sogar für einen einzelnen Spaltenindex von Bedeutung sein, obwohl dies nicht so offensichtlich ist.

Stellen Sie sich einen Index für eine Spalte einer gruppierten Tabelle vor:

CREATE TABLE mytable (
       pk INT NOT NULL PRIMARY KEY,
       col1 INT NOT NULL
)
CREATE INDEX ix_mytable_col1 ON mytable (col1)

Der Index für enthält col1geordnete Werte von col1zusammen mit den Verweisen auf Zeilen.

Da die Tabelle geclustert ist, sind die Verweise auf Zeilen tatsächlich die Werte von pk. Sie sind auch innerhalb jedes Wertes von bestellt col1.

Dies bedeutet, dass die Blätter des Index tatsächlich sortiert sind (col1, pk), und diese Abfrage:

SELECT  col1, pk
FROM    mytable
ORDER BY
        col1, pk

braucht keine Sortierung.

Wenn wir den Index wie folgt erstellen:

CREATE INDEX ix_mytable_col1_desc ON mytable (col1 DESC)

Dann werden die Werte von col1absteigend sortiert, aber die Werte pkinnerhalb jedes Werts von col1werden aufsteigend sortiert.

Dies bedeutet, dass die folgende Abfrage:

SELECT  col1, pk
FROM    mytable
ORDER BY
        col1, pk DESC

kann von serviert werden, ix_mytable_col1_descaber nicht von ix_mytable_col1.

Mit anderen Worten, die Spalten, die eine CLUSTERED INDEXin einer Tabelle bilden, sind immer die nachfolgenden Spalten eines anderen Index in dieser Tabelle.

Quassnoi
quelle
1
Wenn Sie "nicht für ..." sagen, meinen Sie damit, dass es nicht funktioniert oder die Leistung schrecklich sein wird?
Neil N
5
Ich meine, dass der Index nicht für die Abfrage verwendet wird. Die Abfrage selbst funktioniert natürlich, aber die Leistung ist schlecht.
Quassnoi
1
Sollte das zweite Beispiel im ersten Abschnitt nicht "ORDER BY col1 DESC, col2 DESC" lauten?
Mitch Wheat
71

Für einen echten einspaltigen Index macht es aus Sicht des Abfrageoptimierers wenig Unterschied.

Für die Tabellendefinition

CREATE TABLE T1( [ID] [int] IDENTITY NOT NULL,
                 [Filler] [char](8000) NULL,
                 PRIMARY KEY CLUSTERED ([ID] ASC))

Die Abfrage

SELECT TOP 10 *
FROM T1
ORDER BY ID DESC

Verwendet einen geordneten Scan mit Scanrichtung, BACKWARDwie im Ausführungsplan ersichtlich. Es gibt jedoch einen kleinen Unterschied darin, dass derzeit nur FORWARDScans parallelisiert werden können.

Planen

Jedoch kann es einen großen Unterschied in Bezug auf die logische Fragmentierung machen . Wenn der Index mit absteigenden Schlüsseln erstellt wird, aber neue Zeilen mit aufsteigenden Schlüsselwerten angehängt werden, kann jede Seite in logischer Reihenfolge angezeigt werden. Dies kann die Größe der E / A-Lesevorgänge beim Scannen der Tabelle erheblich beeinträchtigen und befindet sich nicht im Cache.

Siehe die Fragmentierungsergebnisse

                    avg_fragmentation                    avg_fragment
name   page_count   _in_percent         fragment_count   _size_in_pages
------ ------------ ------------------- ---------------- ---------------
T1     1000         0.4                 5                200
T2     1000         99.9                1000             1

für das Skript unten

/*Uses T1 definition from above*/
SET NOCOUNT ON;

CREATE TABLE T2( [ID] [int] IDENTITY NOT NULL,
                 [Filler] [char](8000) NULL,
                 PRIMARY KEY CLUSTERED ([ID] DESC))

BEGIN TRAN

GO
INSERT INTO T1 DEFAULT VALUES
GO 1000
INSERT INTO T2 DEFAULT VALUES
GO 1000

COMMIT

SELECT object_name(object_id) AS name, 
       page_count, 
       avg_fragmentation_in_percent, 
       fragment_count, 
       avg_fragment_size_in_pages 
FROM 
sys.dm_db_index_physical_stats(db_id(), object_id('T1'), 1, NULL, 'DETAILED') 
WHERE  index_level = 0 
UNION ALL 
SELECT object_name(object_id) AS name, 
       page_count, 
       avg_fragmentation_in_percent, 
       fragment_count, 
       avg_fragment_size_in_pages 
FROM 
sys.dm_db_index_physical_stats(db_id(), object_id('T2'), 1, NULL, 'DETAILED') 
WHERE  index_level = 0 

Auf der Registerkarte "Räumliche Ergebnisse" können Sie die Annahme überprüfen, dass die späteren Seiten in beiden Fällen aufsteigende Schlüsselwerte aufweisen.

SELECT page_id,
       [ID],
       geometry::Point(page_id, [ID], 0).STBuffer(4)
FROM   T1
       CROSS APPLY sys.fn_PhysLocCracker( %% physloc %% )
UNION ALL
SELECT page_id,
       [ID],
       geometry::Point(page_id, [ID], 0).STBuffer(4)
FROM   T2
       CROSS APPLY sys.fn_PhysLocCracker( %% physloc %% )

Geben Sie hier die Bildbeschreibung ein

Martin Smith
quelle
Vielen Dank, Martin, für diesen tollen
Tipp. Das
Ich frage mich, ob ich einen absteigenden Index habe, und wähle dann mycolumn aus mytable aus, wobei indexed_column = \ @myvalue schneller ist, wenn \ @myvalue näher am maximal möglichen Wert liegt als in dem Fall, in dem \ @myvalue auf den minimal möglichen Wert geschlossen ist.
Lajos Arpad
@LajosArpad warum sollte man schneller sein? B-Bäume sind ausgeglichene Bäume. Die Tiefe des Baumes ist für beide gleich.
Martin Smith
@ MartinSmith die Tiefe ist die gleiche, aber ich bezweifle, dass die Reihenfolge der Geschwister keinen Unterschied machen würde
Lajos Arpad
@MartinSmith, wenn die Reihenfolge der Geschwister nur einen geringen Leistungsunterschied aufweist, würde sich das Ausführen von Millionen von Auswahlen summieren, ganz zu schweigen von mehrdimensionalen Verknüpfungen.
Lajos Arpad
8

Die Sortierreihenfolge ist wichtig, wenn Sie viele sortierte Daten abrufen möchten, nicht einzelne Datensätze.

Beachten Sie, dass (wie Sie mit Ihrer Frage vorschlagen) die Sortierreihenfolge in der Regel weitaus weniger wichtig ist als die von Ihnen indizierten Spalten (das System kann den Index in umgekehrter Reihenfolge lesen, wenn die Reihenfolge der gewünschten entspricht). Ich denke selten über die Reihenfolge der Indexsortierung nach, während ich mich über die vom Index abgedeckten Spalten quäle.

@Quassnoi stellt ein gutes Beispiel , wann es ist egal.

Michael Haren
quelle