Index SQL Server - croissant ou décroissant, quelle différence cela fait-il?

138

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 croissant ou décroissant. 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 quelle commande je choisis?

Joshua Carmody
la source

Réponses:

136

Ceci est principalement important lorsqu'il est utilisé avec des index composites:

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

peut être utilisé 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 de mon blog pour plus de détails:

Mettre à jour:

En fait, cela peut avoir de l'importance même pour un seul index de colonne, même si ce n'est pas si é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 col1conserve les valeurs ordonnées de col1avec les références aux lignes.

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

Cela signifie que les feuilles de l'index sont effectivement ordonnées sur (col1, pk), et cette requête:

SELECT  col1, pk
FROM    mytable
ORDER BY
        col1, pk

n'a pas besoin de tri.

Si nous créons l'index comme suit:

CREATE INDEX ix_mytable_col1_desc ON mytable (col1 DESC)

, alors les valeurs de col1seront triées par ordre décroissant, mais les valeurs de pkdans chaque valeur de col1seront triées par ordre croissant.

Cela signifie que la requête suivante:

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

peut être servi ix_mytable_col1_descmais pas par ix_mytable_col1.

En d'autres termes, les colonnes qui constituent un CLUSTERED INDEXsur n'importe quelle table sont toujours les colonnes de fin de tout autre index de cette table.

Quassnoi
la source
1
Quand vous dites "pas pour ...", voulez-vous dire que cela ne fonctionnera pas ou que la performance sera horrible?
Neil N
5
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 le
1
Dans la première section, le deuxième exemple ne devrait-il pas dire "ORDER BY col1 DESC, col2 DESC"?
Mitch Wheat
71

Pour un véritable index à une seule colonne, cela fait peu de différence du point de vue de l'optimiseur de requêtes.

Pour la définition de la table

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

La requête

SELECT TOP 10 *
FROM T1
ORDER BY ID DESC

Utilise un scan ordonné avec la direction du scan BACKWARDcomme indiqué dans le plan d'exécution. Il y a cependant une légère différence en ce que seuls les FORWARDscans peuvent actuellement être parallélisés.

Plan

Cependant, cela 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é ascendantes, vous pouvez vous retrouver avec chaque page dans le désordre logique. Cela peut avoir un impact important sur la taille des lectures d'E / S lors de l'analyse de la table et elle n'est pas dans le cache.

Voir les résultats de la fragmentation

                    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 des résultats spatiaux pour vérifier la supposition que cela est dû au fait que les pages suivantes ont des valeurs de clé croissantes dans 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 %% )

entrez la description de l'image ici

Martin Smith
la source
Merci Martin pour ce bon TIP, cela m'a vraiment aidé dans les requêtes de classement
TheGameiswar
Je me demande si j'ai un index décroissant, puis sélectionnez mycolumn dans mytable où indexed_column = \ @myvalue est plus rapide lorsque \ @myvalue est plus proche de la valeur maximale possible que dans le cas où \ @myvalue est fermé à la valeur minimale possible.
Lajos Arpad
@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.
Martin Smith
@MartinSmith la profondeur est la même, mais je doute que l'ordre des frères et sœurs ne fasse pas de différence
Lajos Arpad
@MartinSmith, si l'ordre des frères et sœurs présente une légère différence de performances, l'exécution de millions de sélections s'additionnerait, sans parler des jointures multidimensionnelles.
Lajos Arpad
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 significatif que les colonnes que vous indexez (le système peut lire l'index en sens inverse si l'ordre est opposé à ce qu'il veut). Je pense rarement à l'ordre de tri de l'index, alors que je m'inquiète des colonnes couvertes par l'index.

@Quassnoi fournit un excellent exemple de quand il n'importe.

Michael Haren
la source