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 même ici. En utilisant des techniques de tri binaire, une recherche ne serait-elle pas aussi rapide dans les deux cas? Quelle différence cela fait-il quelle commande je choisis?
Cela importe surtout 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 efficacement utilisé pour trier dans les deux sens.
Voir l'article sur mon blog pour plus de détails:
Mise à jour:
En fait, cela peut avoir de l'importance même pour un index de colonne unique, bien que ce ne soit 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 col1
conserve les valeurs ordonnées de col1
avec les références aux lignes.
Puisque la table est en cluster, les références aux lignes sont en réalité les valeurs de pk
. Ils sont également classés dans chaque valeur de col1
.
Cela signifie que les feuilles de l'index sont en réalité ordonnées sur (col1, pk)
, et cette requête:
SELECT col1, pk
FROM mytable
ORDER BY
col1, pk
pas besoin de trier.
Si nous créons l'index comme suit:
CREATE INDEX ix_mytable_col1_desc ON mytable (col1 DESC)
, alors les valeurs de col1
sera trié par ordre décroissant, mais les valeurs de pk
dans chaque valeur de col1
sera trié par ordre 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 un CLUSTERED INDEX
sur une table, figurent toujours les colonnes de fin de tout autre index de cette table.
Pour un véritable index de colonne unique, cela ne fait guère de différence du point de vue de l'Optimiseur de requête.
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 une analyse ordonnée avec le sens d'analyse BACKWARD
comme indiqué dans le plan d'exécution. Il y a cependant une légère différence dans le fait qu'actuellement, seuls les scans FORWARD
peuvent être parallélisés.
Cependant cela peut faire une grande différence en termes de fragmentation logique. Si l'index est créé avec des clés descendantes mais que les nouvelles lignes sont ajoutées avec des valeurs de clé croissantes, vous pouvez vous retrouver avec chaque page en dehors de l'ordre logique. Cela peut avoir un impact important sur la taille de la IO lit lors de l'analyse de la table et celle-ci 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 de résultats spatiaux pour vérifier si cela est supposé, car 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 %% )
L'ordre de tri est important lorsque vous souhaitez extraire un grand nombre de 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 opposé). Je ne pense que très rarement à l'ordre de tri des index, alors que j'agonise les colonnes couvertes par l'index.
@Quassnoi fournit un bon exemple pour savoir quand est important .