2009-04-13 8 views
102

Lorsque vous créez un index sur une colonne ou un nombre de colonnes dans MS SQL Server (j'utilise la version 2005), vous pouvez spécifier que l'index de chaque colonne soit ascendant ou descendant. J'ai du mal à comprendre pourquoi ce choix est encore là. En utilisant des techniques de tri binaire, une recherche ne serait-elle pas aussi rapide de toute façon? Quelle différence cela fait-il quel ordre je choisis?Index SQL Server - croissant ou décroissant, quelle différence cela fait-il?

Répondre

105

Ce point est important surtout quand il est utilisé avec des indices composites:

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

peuvent être utilisés soit pour:

SELECT * 
FROM mytable 
ORDER BY 
     col1, col2 DESC 

ou:

SELECT * 
FROM mytable 
ORDER BY 
     col1 DESC, col2 

, mais pas pour:

SELECT * 
FROM mytable 
ORDER BY 
     col1, col2 

Un index sur une seule colonne peut être utilisé efficacement pour le tri dans les deux sens.

Voir l'article dans mon blog pour plus de détails:

Mise à jour:

En fait, cela peut compter, même pour un indice de colonne unique, bien que ce n'est pas tellement évident.

Imaginez un index sur une colonne d'une table en cluster:

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

L'index sur col1 continue des valeurs ordonnées de col1 ainsi que les références à des lignes.

Étant donné que la table est mise en cluster, les références aux lignes correspondent en fait aux valeurs de pk. Ils sont également classés dans chaque valeur de col1.

Cela signifie que que les feuilles de l'indice sont effectivement commandés sur (col1, pk), et cette requête:

SELECT col1, pk 
FROM mytable 
ORDER BY 
     col1, pk 

besoins sans tri.

Si nous créons l'index comme suit:

CREATE INDEX ix_mytable_col1_desc ON mytable (col1 DESC) 

, les valeurs de col1 seront triées descendant, mais les valeurs de pk dans chaque valeur de col1 seront triés croissant.

Cela signifie que la requête suivante:

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

peut être servi par ix_mytable_col1_desc mais pas par ix_mytable_col1. En d'autres termes, les colonnes qui constituent CLUSTERED INDEX sur n'importe quelle table sont toujours les colonnes finales de tout autre index de cette table.

+0

Quand vous dites « pas ... » Voulez-vous dire cela ne fonctionnera pas ou la performance sera horrible? –

+2

Je veux dire que l'index ne sera pas utilisé pour la requête. La requête elle-même fonctionnera, bien sûr, mais les performances seront médiocres. – Quassnoi

+0

Dans la première section, le deuxième exemple ne devrait-il pas indiquer "ORDER BY col1 DESC, col2 DESC"? –

8

L'ordre de tri est important lorsque vous souhaitez récupérer de nombreuses données triées, et non des enregistrements individuels. Notez que (comme vous le suggérez avec votre question) l'ordre de tri est généralement beaucoup moins important que les colonnes que vous indexez (le système peut lire l'index à l'envers si l'ordre est contraire à ce qu'il veut). Je donne rarement une idée à l'ordre de tri de l'index, alors que je agonise sur les colonnes couvertes par l'index.

@Quassnoi fournit un great example de quand fait matière.

53

Pour un véritable index de colonne unique, cela ne fait pas de grande différence du point de vue de l'Optimiseur de requête.

Pour la définition de table

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

Le Query

SELECT TOP 10 * 
FROM T1 
ORDER BY ID DESC 

Utilise une analyse commandée avec la direction de balayage BACKWARD comme on peut le voir dans le plan d'exécution. Il existe cependant une légère différence en ce sens que seuls les balayages FORWARD peuvent être parallélisés.

Plan

Cependant il peut faire une grande différence en termes de fragmentation logique. Si l'index est créé avec des clés décroissantes mais que de nouvelles lignes sont ajoutées avec des valeurs de clé croissantes, vous pouvez vous retrouver avec chaque page hors de l'ordre logique. Cela peut gravement affecter la taille des lectures d'E/S lors de l'analyse de la table et n'est pas dans le cache.

Voir la fragmentation résulte

    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 

pour le script ci-dessous

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

Il est possible d'utiliser l'onglet résultats spatiaux afin de vérifier la supposition que ce soit parce que les pages suivantes ont par ordre croissant des valeurs clés les deux cas.

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

Merci Martin pour cet excellent TIP, cela m'a vraiment aidé dans les requêtes de classement – TheGameiswar

+0

Je me demande si j'ai un index descendant, puis sélectionnez mycolumn depuis mytable où indexed_column = \ @myvalue est plus rapide quand \ @myvalue est plus proche de la valeur maximale possible que dans le cas où \ @myvalue est fermé à la valeur minimale possible. –

+0

@LajosArpad pourquoi serait-on plus rapide? Les arbres B sont des arbres équilibrés.La profondeur de l'arbre est la même pour les deux. –

Questions connexes