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.