2009-04-13 5 views
102

Wenn Sie einen Index für eine Spalte oder eine Anzahl von Spalten in MS SQL Server erstellen (ich verwende Version 2005), können Sie angeben, dass der Index für jede Spalte entweder aufsteigend oder absteigend sein soll. Es fällt mir schwer zu verstehen, warum diese Entscheidung auch hier ist. Mit binären Sort-Techniken, würde ein Lookup nicht so schnell sein? Welchen Unterschied macht es, welche Reihenfolge ich wähle?SQL Server-Indizes - aufsteigend oder absteigend, welchen Unterschied macht es?

Antwort

105

Dies ist wichtig, vor allem, wenn sie mit zusammengesetzten Indizes verwendet:

SELECT * 
FROM mytable 
ORDER BY 
     col1, col2 DESC 

oder:

SELECT * 
FROM mytable 
ORDER BY 
     col1 DESC, col2 

, aber nicht für:

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

kann entweder verwendet werden,

SELECT * 
FROM mytable 
ORDER BY 
     col1, col2 

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

Siehe den Artikel in meinem Blog für Details:

Update:

In der Tat ist dies auch nur für einen Spaltenindex Materie kann, obwohl es nicht ist so offensichtlich.

einen Index für eine Spalte einer Clustertabelle Stellen:

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

Der Index auf col1 hält sich an Zeilen mit den Werten von Referenzen col1 entlang bestellt.

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

Dies bedeutet, dass der des Index lässt auf (col1, pk) tatsächlich bestellt haben, und diese Abfrage:

SELECT col1, pk 
FROM mytable 
ORDER BY 
     col1, pk 

braucht keine Sortierung.

Wenn wir erstellen den Index, wie folgend:

CREATE INDEX ix_mytable_col1_desc ON mytable (col1 DESC) 

, dann werden die Werte von col1 absteigend sortiert werden, aber die Werte von pk innerhalb jeder Wert von col1 wird aufsteigend sortiert werden. Das bedeutet,

, dass die folgende Abfrage:

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

kann durch ix_mytable_col1_desc aber nicht von ix_mytable_col1 serviert werden.

Mit anderen Worten, die Spalten, die eine CLUSTERED INDEX für eine beliebige Tabelle bilden, sind immer die nachlaufenden Spalten eines anderen Index für diese Tabelle.

+0

Wenn Sie sagen, „nicht für ...“ Meinen Sie, es wird nicht funktionieren oder die Leistung wird schrecklich sein? –

+2

Ich meine, dass der Index nicht für die Abfrage verwendet wird. Die Abfrage selbst wird natürlich funktionieren, aber die Leistung wird schlecht sein. – Quassnoi

+0

Im ersten Abschnitt sollte das zweite Beispiel nicht sagen "ORDER BY col1 DESC, col2 DESC"? –

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 weniger wichtig ist als die Spalten, die Sie indexieren (das System kann den Index umgekehrt anzeigen, wenn die Reihenfolge entgegengesetzt ist). Ich gebe der Index-Sortierreihenfolge kaum einen Gedanken, während ich mich über die vom Index abgedeckten Spalten quäle.

@Quassnoi bietet eine great example von wann es tut Angelegenheit.

53

Für einen echten einzelnen Spaltenindex unterscheidet es wenig aus der Sicht des Abfrageoptimierers.

Für die Tabellendefinition

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

Der Query

SELECT TOP 10 * 
FROM T1 
ORDER BY ID DESC 

Verwendet eine geordnete Scan mit Scan-Richtung BACKWARD wie in den Ausführungsplan zu sehen. Ein kleiner Unterschied besteht jedoch darin, dass derzeit nur FORWARD Scans parallelisiert werden können.

Plan

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, können Sie jede Seite in der logischen Reihenfolge beenden. Dies kann die Größe der IO-Lesevorgänge beim Scannen der Tabelle stark beeinträchtigen und befindet sich nicht im Cache.

Siehe die Fragmentierung

    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 unter

/*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 

Ergebnisse Es ist möglich, die räumliche Ergebnisse Tab zu verwenden, um die Vermutung zu bestätigen, dass dies, weil die späteren Seiten Schlüsselwerte haben aufsteigend in beide Fälle.

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 %%) 

enter image description here

+0

Vielen Dank Martin für diesen tollen Tipp, das hat mir wirklich in Rangabfragen geholfen – TheGameiswar

+0

Ich frage mich, ob ich einen absteigenden Index habe, dann mycolumn aus mytable where indexed_column = \ @myvalue ist schneller, wenn \ @myvalue näher am maximal möglichen Wert ist als in dem Fall, wenn \ @myvalue auf den minimal möglichen Wert geschlossen ist. –

+0

@LajosArpad warum wäre man schneller? B Bäume sind ausgeglichene Bäume.Die Tiefe des Baumes ist für beide gleich. –

Verwandte Themen