web-dev-qa-db-fra.com

Quels facteurs entrent dans un indice groupé d'une vue indexée sélectionné?

brièvement
[.____] quels facteurs vont-ils dans la sélection de l'indice d'une vue d'une vue indexée?

Pour moi, des vues indexées semblent défier ce que je comprends de la manière dont l'optimiseur choisit les index. J'ai vu cela a demandé auparavant , mais l'OP n'était pas trop bien reçu. Je cherche vraiment des guides, mais je vais concocter un pseudo exemple, puis postez un exemple réel avec beaucoup de DDL, sortie, exemples.

Supposons que j'utilise Enterprise 2008+, comprenez with(noexpand)

Exemple de pseudo

Prenez cet exemple de pseudo: je crée une vue avec 22 jointures, 17 filtres et un poney de cirque qui traverse un tas de tables de 10 millions de rangées. Cette vue est chère (Yep, avec une capitale E) de se matérialiser. Je serai schématiquement et indexez la vue. Puis un SELECT a,b FROM AnIndexedView WHERE theClusterKeyField < 84. Dans la logique d'optimisation qui m'éludote, les jointures sous-jacentes sont effectuées.

Le résultat:

  • Aucun indice: 4825 se lit sur 720 lignes, 47 CPU sur 76 ms et un coût de sous-arbre estimé de 0,30523.
  • Avec Astuce: 17 Lit, 720 lignes, 15 CPU sur 4 ms et un coût de sous-groupe estimé de 0,007253

Alors qu'est-ce qui se passe ici? Je l'ai essayé in Entreprise 2008, 2008-R2 et 2012. Par chaque métrique, je pense que l'utilisation de l'indice de l'avis est considérablement plus efficace. Je n'ai pas de problème de reniflement des paramètres ni de données asymétriques, car il s'agit de l'annonce.

Un vrai (long) exemple

Sauf si vous êtes une touche masochiste, vous n'avez probablement pas besoin de lire cette partie.

la version
oui, entreprise.

Microsoft SQL Server 2012 - 11.0.2100.60 (X64) 10 févr. 2012 19:39:15 Copyright (c) Microsoft Corporation Enterprise Edition (64 bits) sur Windows NT 6.2 (Buildrovish 9200 :) (Hypervisor)

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 en cluster

CREATE UNIQUE CLUSTERED INDEX PK_TimelineMaterialized  ON 
                   TimelineMaterialized (EmployeeID, CreateUTC, CultureCode, TimelineID)

Test 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 rangées de sortie

11 rows of output - same for both queries

Sortie du profileur
[.____] Les 4 lignes supérieures sont sans indice. Les 4 lignes inférieures utilisent l'indice.

Profiler

Plans d'exécution
[.____] GIST GITUB pour les deux plans d'exécution au format SQLPLAN

Aucun plan d'exécution d'indice - Pourquoi ne pas utiliser l'index en cluster, je vous ai donné M. SQL? C'est Clusterd sur les 3 champs de filtrage. Essayez-le, vous pourriez aimer.
No Hint - huge execution plan

Plan simple lorsque vous utilisez un indice.

Using Hint - Simple Execution Plan

19
EBarr

Les vues indexées correspondantes sont 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'il en a sauvegardé. N'oubliez pas que l'objectif principal de l'optimiseur est un plan "assez bon" rapidement.

en utilisant L'index en cluster sur la vue n'est pas coûteux en soi, mais le processus de correspondance d'une arborescence de requête logique à des vues indexées potentielles peut ê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, l'optimiseur ne sait pas que vous avez écrit la requête contre la vue en premier lieu - elle ne voit que l'arbre expansé (comme si la vue avait été intégré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 un "budget" au début de la phase actuelle.

Le budget est défini sur la base du coût du meilleur plan trouvé lors d'une phase précédente. Avec une telle requête à faible coût (0,05), le nombre de mouvements budgétisés sera assez petit et rapidement épuisé par une transformation régulière compte tenu du nombre de jointures impliquées dans votre requête d'échantillon (il existe de nombreuses façons de réorganiser les jointures intérieures, par exemple) .

Si vous êtes intéressé à en savoir plus sur la raison pour laquelle la correspondance d'une vue indexée coûte cher, et donc laissée pour des étapes ultérieures d'optimisation et/ou uniquement de requêtes plus coûteuses, il existe deux documents de recherche Microsoft sur le sujet ici (PDF) et ici (Citeser).

Un autre facteur pertinent est que la correspondance d'une vue indexée n'est pas disponible en phase d'optimisation 0 (traitement de la transaction).

En plus de lecture:

Vues indexées et statistiques

* et uniquement disponible dans Enterprise Edition (ou équivalent)

26
Paul White 9