En bref
Quels facteurs entrent en jeu lorsqu'ils interrogent l'optimiseur sur la sélection de l'index d'une vue indexée?
Pour moi, les vues indexées semblent défier ce que je comprends de la façon dont l'Optimizer sélectionne les index. J'ai déjà vu cette question , mais le PO n'a pas été bien reçu. Je suis vraiment à la recherche de repères , mais je vais concocter un pseudo exemple, puis poster un exemple réel avec beaucoup de DDL, des sorties, des exemples.
Supposons que j'utilise Enterprise 2008+, comprenez
with(noexpand)
Pseudo-exemple
Prenons ce pseudo-exemple: je crée une vue avec 22 jointures, 17 filtres et un poney de cirque qui traverse un tas de 10 millions de tables de lignes. Cette vue est coûteuse (oui, avec un E majuscule) pour se matérialiser. Je vais SCHEMABIND et indexer la vue. Alors a SELECT a,b FROM AnIndexedView WHERE theClusterKeyField < 84
. Dans la logique Optimizer qui m'échappe, les jointures sous-jacentes sont effectuées.
Le résultat:
- Pas d'indice: 4825 lectures pour 720 lignes, 47 processeurs sur 76 ms et un coût estimé de sous-arbre de 0,30523.
- Avec indice: 17 lectures, 720 lignes, 15 processeurs sur 4 ms et un coût estimé des sous-arbres de 0,007253
Alors qu'est-ce qui se passe ici? Je l'ai essayé dans Enterprise 2008, 2008-R2 et 2012. Par chaque métrique, je peux penser que l'utilisation de l'index de la vue est beaucoup plus efficace. Je n'ai pas de problème de reniflage de paramètres ou de données biaisées, car il s'agit de jarrets publicitaires.
Un vrai (long) exemple
Sauf si vous êtes un peu masochiste, vous n'avez probablement pas besoin ou ne voulez pas lire cette partie.
La version
Yep, entreprise.
Microsoft SQL Server 2012 - 11.0.2100.60 (X64) 10 février 2012 19:39:15 Copyright (c) Microsoft Corporation Enterprise Edition (64 bits) sur Windows NT 6.2 (Build 9200:) (Hyperviseur)
La vue
CREATE VIEW dbo.TimelineMaterialized WITH SCHEMABINDING
AS
SELECT TM.TimelineID,
TM.TimelineTypeID,
TM.EmployeeID,
TM.CreateUTC,
CUL.CultureCode,
CASE
WHEN TM.CustomerMessageID > 0 THEN TM.CustomerMessageID
WHEN TM.CustomerSessionID > 0 THEN TM.CustomerSessionID
WHEN TM.NewItemTagID > 0 THEN TM.NewItemTagID
WHEN TM.OutfitID > 0 THEN TM.OutfitID
WHEN TM.ProductTransactionID > 0 THEN TM.ProductTransactionID
ELSE 0 END As HrefId,
CASE
WHEN TM.CustomerMessageID > 0 THEN IsNull(C.Name, 'N/A')
WHEN TM.CustomerSessionID > 0 THEN IsNull(C.Name, 'N/A')
WHEN TM.NewItemTagID > 0 THEN IsNull(NI.Title, 'N/A')
WHEN TM.OutfitID > 0 THEN IsNull(O.Name, 'N/A')
WHEN TM.ProductTransactionID > 0 THEN IsNull(PT_PL.NameLocalized, 'N/A')
END as HrefText
FROM dbo.Timeline TM
INNER JOIN dbo.CustomerSession CS ON TM.CustomerSessionID = CS.CustomerSessionID
INNER JOIN dbo.CustomerMessage CM ON TM.CustomerMessageID = CM.CustomerMessageID
INNER JOIN dbo.Outfit O ON PO.OutfitID = O.OutfitID
INNER JOIN dbo.ProductTransaction PT ON TM.ProductTransactionID = PT.ProductTransactionID
INNER JOIN dbo.Product PT_P ON PT.ProductID = PT_P.ProductID
INNER JOIN dbo.ProductLang PT_PL ON PT_P.ProductID = PT_PL.ProductID
INNER JOIN dbo.Culture CUL ON PT_PL.CultureID = CUL.CultureID
INNER JOIN dbo.NewsItemTag NIT ON TM.NewsItemTagID = NIT.NewsItemTagID
INNER JOIN dbo.NewsItem NI ON NIT.NewsItemID = NI.NewsItemID
INNER JOIN dbo.Customer C ON C.CustomerID = CASE
WHEN TM.TimelineTypeID = 1 THEN CM.CustomerID
WHEN TM.TimelineTypeID = 5 THEN CS.CustomerID
ELSE 0 END
WHERE CUL.IsActive = 1
Index clusterisé
CREATE UNIQUE CLUSTERED INDEX PK_TimelineMaterialized ON
TimelineMaterialized (EmployeeID, CreateUTC, CultureCode, TimelineID)
Tester SQL
-- NO HINT - - - - - - - - - - - - - - -
SELECT * --yes yes, star is bad ...just a test example
FROM TimelineMaterialized TM
WHERE
TM.EmployeeID = 2
AND TM.CultureCode = 'en-US'
AND TM.CreateUTC > '9/10/2012'
AND TM.CreateUTC < '9/11/2012'
-- WITH HINT - - - - - - - - - - - - - - -
SELECT *
FROM TimelineMaterialized TM with(noexpand)
WHERE
TM.EmployeeID = 2
AND TM.CultureCode = 'en-US'
AND TM.CreateUTC > '9/10/2012'
AND TM.CreateUTC < '9/11/2012'
Résultat = 11 lignes de sortie
Sortie du profileur
Les 4 premières lignes sont sans indice. Les 4 dernières lignes utilisent l'indice.
Plans d'exécution
GitHub Gist pour les deux plans d'exécution au format SQLPlan
No Hint Execution plan - pourquoi ne pas utiliser l'index cluster que je vous ai donné Mr. SQL? C'est clusterd sur les 3 champs de filtre. Essayez-le, vous pourriez aimer.
Plan simple lors de l'utilisation d'un indice.
Réponses:
La correspondance des vues indexées est une opération relativement coûteuse *, l'optimiseur essaie donc d'abord d'autres transformations rapides et faciles. Si ceux-ci produisent un plan bon marché (0,05 unités dans votre cas), l'optimisation se termine tôt. Le pari est que l'optimisation continue consommerait plus de temps qu'elle n'en a économisé. N'oubliez pas que l'objectif principal de l'optimiseur est un plan «assez bon» rapidement.
L'utilisation de l'index cluster sur la vue n'est pas coûteuse en soi, mais le processus de mise en correspondance d'un arbre de requête logique avec des vues indexées potentielles peut l'être. Comme je l'ai mentionné dans un commentaire sur l'autre question, la référence de vue dans la requête est développée avant l'optimisation, de sorte que l'optimiseur ne sait pas que vous avez écrit la requête sur la vue en premier lieu - il ne voit que l'arborescence développée (comme si la vue avait été alignée).
«Bon plan suffisant» signifie que l'optimiseur a trouvé un plan décent et s'est arrêté tôt dans une phase d'exploration. «TimeOut» signifie qu'il a dépassé le nombre d'étapes d'optimisation qu'il s'est fixé comme «budget» au début de la phase en cours.
Le budget est établi en fonction du coût du meilleur plan trouvé dans une phase précédente. Avec une requête aussi peu coûteuse (0,05), le nombre de mouvements budgétés sera assez petit et rapidement épuisé par une transformation régulière étant donné le nombre de jointures impliquées dans votre exemple de requête (il existe de nombreuses façons de réorganiser les jointures internes, par exemple) .
Si vous souhaitez en savoir plus sur les raisons pour lesquelles la correspondance des vues indexées est coûteuse, et donc réservée aux étapes ultérieures d'optimisation et / ou uniquement envisagée pour les requêtes plus coûteuses, il existe deux documents de recherche Microsoft sur le sujet ici (pdf) et ici (citeseer ).
Un autre facteur pertinent est que la correspondance des vues indexées n'est pas disponible dans la phase d'optimisation 0 (traitement des transactions).
Lectures complémentaires:
Vues et statistiques indexées
* et uniquement disponible dans Enterprise Edition (ou équivalent)
la source