Pourquoi l'optimiseur choisirait-il l'index clusterisé + trier plutôt que l'index non clusterisé?

11

Étant donné l'exemple suivant:

IF OBJECT_ID('dbo.my_table') IS NOT NULL
    DROP TABLE [dbo].[my_table];
GO

CREATE TABLE [dbo].[my_table]
(
    [id]    int IDENTITY (1,1)  NOT NULL PRIMARY KEY,
    [foo]   int                 NULL,
    [bar]   int                 NULL,
    [nki]   int                 NOT NULL
);
GO

/* Insert some random data */
INSERT INTO [dbo].[my_table] (foo, bar, nki)
SELECT TOP (100000)
    ABS(CHECKSUM(NewId())) % 14,
    ABS(CHECKSUM(NewId())) % 20,
    n = CONVERT(INT, ROW_NUMBER() OVER (ORDER BY s1.[object_id]))
FROM 
    sys.all_objects AS s1 
CROSS JOIN 
    sys.all_objects AS s2
GO

CREATE UNIQUE NONCLUSTERED INDEX [IX_my_table]
    ON [dbo].[my_table] ([nki] ASC);
GO

Si je récupère tous les enregistrements classés par [nki](index non cluster):

SET STATISTICS TIME ON;
SELECT id, foo, bar, nki FROM my_table ORDER BY nki;
SET STATISTICS TIME OFF;

SQL Server Execution Times: CPU time = 266 ms, elapsed time = 493 ms

L'optimiseur choisit l'index clusterisé puis applique un algorithme de tri.

entrez la description de l'image ici

Execution plan

Mais si je le force à utiliser l'index non clusterisé:

SET STATISTICS TIME ON;
SELECT id, foo, bar, nki FROM my_table WITH(INDEX(IX_my_TABLE));
SET STATISTICS TIME OFF;

SQL Server Execution Times: CPU time = 311 ms, elapsed time = 188 ms

Ensuite, il utilise un index non cluster avec une recherche de clé:

entrez la description de l'image ici

Execution plan

Évidemment, si l'index non clusterisé est transformé en index couvrant:

CREATE UNIQUE NONCLUSTERED INDEX [IX_my_table]
    ON [dbo].[my_table] ([nki] ASC)
    INCLUDE (id, foo, bar);
GO

Ensuite, il utilise uniquement cet index:

SET STATISTICS TIME ON;
SELECT id, foo, bar, nki FROM my_table ORDER BY nki;
SET STATISTICS TIME OFF;

SQL Server Execution Times: CPU time = 32 ms, elapsed time = 106 ms

entrez la description de l'image ici

Execution plan


Question

  • Pourquoi SQL Server utilise-t-il l'index clusterisé plus un algorithme de tri au lieu d'utiliser un index non clusterisé même si le temps d'exécution est 38% plus rapide dans ce dernier cas?
McNets
la source
1
Vouliez-vous laisser de côté ORDER BY dans votre requête d'indexation forcée?
Forrest

Réponses:

9

Pourquoi SQL Server utilise-t-il l'index clusterisé plus un algorithme de tri au lieu d'utiliser un index non clusterisé même si le temps d'exécution est 38% plus rapide dans ce dernier cas?

Parce que SQL Server utilise un optimiseur basé sur les coûts basé sur des statistiques et non sur des informations d'exécution.

Au cours du processus d'estimation des coûts pour cette requête, il évalue réellement le plan de recherche, mais estime qu'il faudra plus d'efforts. (Notez le «coût estimé des sous-arbres» lorsque vous survolez SELECT dans le plan d'exécution). Ce n'est pas nécessairement une mauvaise hypothèse non plus - sur ma machine de test, le plan de recherche prend 6 fois le processeur du tri / scan.

Consultez la réponse de Rob Farley pour savoir pourquoi SQL Server pourrait coûter plus cher au plan de recherche.

Forrest
la source
9

Si vous deviez comparer le nombre de lectures requises dans 100 000 recherches avec ce qui est impliqué dans le tri, vous pourriez rapidement vous faire une idée de pourquoi l'Optimiseur de requête estime que le tri CIX + serait le meilleur choix.

L'exécution de la recherche finit par être plus rapide car les pages lues sont en mémoire (même si vous videz le cache, vous avez beaucoup de lignes par page, donc vous lisez les mêmes pages encore et encore, mais avec différentes quantités de fragmentation ou une pression de mémoire différente d'une autre activité, cela pourrait ne pas être le cas). Cela ne prendrait pas beaucoup de temps pour que CIX + Sort soit plus rapide, mais ce que vous voyez est que le coût d'une lecture ne prend pas en compte le coût relativement bas de frapper les mêmes pages à plusieurs reprises.

Rob Farley
la source
4

J'ai décidé de creuser un peu sur cette question et j'ai découvert des documents intéressants parlant de comment et quand utiliser ou peut-être mieux, pas (forcer) l'utilisation d'un index non clusterisé.

Comme suggéré par les commentaires de John Eisbrener , l'un des articles les plus référencés, même dans d'autres blogs, est cet article intéressant de Kimberly L. Tripp:

mais ce n'est pas le seul, si vous êtes intéressé, vous pouvez jeter un œil à ces pages:

Comme vous pouvez le voir, tous se déplacent autour du concept du point de basculement .

Extrait d'un article de KL Tripp

Quel est le point de basculement?

C'est le point où le nombre de lignes retournées n'est " plus assez sélectif ". SQL Server choisit de NE PAS utiliser l'index non cluster pour rechercher les lignes de données correspondantes et effectue à la place une analyse de table.

Lorsque SQL Server utilise un index non cluster sur un segment de mémoire, il obtient essentiellement une liste de pointeurs vers les pages de la table de base. Il utilise ensuite ces pointeurs pour récupérer les lignes avec une série d'opérations appelées Row ID Lookups (RID). Cela signifie qu'au moins, il utilisera autant de pages lues que le nombre de lignes renvoyées, et peut-être plus. Le processus est quelque peu similaire avec un index clusterisé comme la table de base, avec le même résultat: plus de lectures.

Mais, quand ce point de basculement se produit?

Bien sûr, comme la plupart des choses dans cette vie, cela dépend ...

Non sérieusement, cela se produit entre 25% et 33% du nombre de pages du tableau, selon le nombre de lignes par page. Mais il y a plus de facteurs à considérer:

Extrait d'un article d'ITPRoToday

Autres facteurs affectant le point de basculement Bien que le coût des recherches RID soit le facteur le plus important qui affecte le point de basculement, il existe un certain nombre d'autres facteurs:

  • Les E / S physiques sont beaucoup plus efficaces lors de l'analyse d'un index clusterisé. Les données d'index cluster sont placées séquentiellement sur le disque dans l'ordre d'index. Par conséquent, il y a très peu de déplacement latéral de la tête sur le disque, ce qui améliore les performances d'E / S.
  • Lorsque le moteur de base de données analyse un index clusterisé, il sait qu'il existe une forte probabilité que les prochaines pages de la piste de disque contiennent toujours les données dont il a besoin. Ainsi, il commence à lire en morceaux de 64 Ko au lieu des pages normales de 8 Ko. Cela se traduit également par des E / S plus rapides.

Maintenant, si j'exécute à nouveau mes requêtes à l'aide de statistiques IO:

SET STATISTICS IO ON;
SELECT id, foo, bar, nki FROM my_table WHERE nki < 20000 ORDER BY nki ;
SET STATISTICS IO OFF;

Logical reads: 312

SET STATISTICS IO ON;
SELECT id, foo, bar, nki FROM my_table WITH(INDEX(IX_my_TABLE));
SET STATISTICS IO OFF;

Logical reads: 41293

La deuxième requête nécessite plus de lectures logiques que la première.

Dois-je éviter l'index non cluster?

Non, un index clusterisé peut être utile, mais cela vaut la peine de prendre du temps et de faire un effort supplémentaire pour analyser ce que vous essayez de réaliser avec.

Extrait d'un article de KL Tripp

Alors, que devrais-tu faire? Ça dépend. Si vous connaissez bien vos données et que vous effectuez des tests approfondis, vous pourriez envisager d'utiliser un indice (il y a des choses intelligentes que vous pouvez faire par programme dans sps, je vais essayer de dédier un article à cela bientôt). Cependant, un bien meilleur choix (si possible) est d'envisager de couvrir (c'est vraiment mon point principal :). Dans mes requêtes, la couverture est irréaliste parce que mes requêtes veulent toutes les colonnes (le mauvais SELECT *) mais, si vos requêtes sont plus étroites ET qu'elles sont de haute priorité, vous feriez mieux avec un index de couverture (dans de nombreux cas) sur un indice parce que un index qui couvre une requête, jamais des conseils.

C'est la réponse au puzzle pour l'instant, mais il y a certainement beaucoup plus à plonger. Le point de basculement peut être une très bonne chose - et il fonctionne généralement bien. Mais, si vous constatez que vous pouvez forcer un index et obtenir de meilleures performances, vous voudrez peut-être faire des recherches et voir si c'est le cas. Considérez ensuite la probabilité qu'un indice soit utile et vous savez maintenant où vous pouvez vous concentrer.

McNets
la source