Які фактори входять до вибраного індексу кластеризованого індексу індексованого виду?


19

Коротко
Які фактори враховують вибір запиту оптимізатора на індекс індексованого перегляду?

Для мене, здається, індексовані подання не піддаються тому, що я розумію щодо того, як оптимізатор вибирає індекси. Я вже бачив, як це запитували раніше , але ОП не надто добре сприйняли. Я дійсно шукаю путівники , але буду придумувати псевдоприклад, а потім публікувати реальний приклад з великою кількістю DDL, вихідних даних, прикладів.

Припустимо, я використовую Enterprise 2008+, зрозумійте with(noexpand)

Приклад псевдо

Візьмемо цей псевдоприклад: я створюю представлення з 22 приєднаннями, 17 фільтрами та цирковим поні, що перетинає купу 10 мільйонів рядкових таблиць. Цей погляд дорого реалізується (так, з великою літерою Е). Я SCHEMABIND та індексувати подання. Тоді а SELECT a,b FROM AnIndexedView WHERE theClusterKeyField < 84. У логіці оптимізатора, яка ухиляється від мене, виконуються основні з'єднання.

Результат:

  • Ні підказки: 4825 читає 720 рядків, 47 процесорних процесорів за 76 мс, а орієнтовна вартість нижнього дерева - 0,30523.
  • З підказкою: 17 читань, 720 рядків, 15 процесорних процесорів за 4 мс, а орієнтовна вартість нижнього дерева - 0,007253

То що тут відбувається? Я спробував це в Enterprise 2008, 2008-R2 та 2012. За кожною метрикою, яку я можу подумати, використовуючи індекс перегляду, набагато ефективніше. У мене немає проблеми з обнюхуванням параметрів або перекошеними даними, оскільки це скачування.

Справжній (довгий) приклад

Якщо ви не дотик мазохіст, вам, мабуть, не потрібна чи хочете читати цю частину.

Версія
Yep, підприємство.

Microsoft SQL Server 2012 - 11.0.2100.60 (X64) 10 лютого 2012 19:39:15 Авторські права (c) Microsoft Corporation Enterprise Edition (64-розрядні) на Windows NT 6.2 (Build 9200:) (Hypervisor)

Вид

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

Індекс кластера

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

Тест 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'

Результат = 11 рядків результату

11 рядків виводу - однакові для обох запитів

Вихід профайлера
Найкращі 4 рядки не мають підказки. Нижні 4 рядки використовують підказку.

Профілер

Плани виконання
GitHub Gist для обох планів виконання у форматі SQLPlan

Немає плану виконання підказок - чому б не використати кластерний індекс, який я дав вам містерові SQL? Він згрупований на 3 фільтрувальних полях. Спробуйте, можливо, вам сподобається.
Без підказки - величезний план виконання

Простий план при використанні підказки.

Використання підказки - простий план виконання


Відповіді:


26

Відповідність індексованих представлень - відносно дорога операція *, тому оптимізатор спочатку спробує інші швидкі та легкі перетворення. Якщо у них трапиться дешевий план (у вашому випадку 0,05 одиниці), оптимізація закінчується рано. Зрозуміло, що подальша оптимізація потребує більше часу, ніж заощаджена. Пам'ятайте, головна мета оптимізатора - досить "хороший" план.

Використання кластерного індексу в представленні само по собі не є дорогим, але процес узгодження дерева логічних запитів з потенційними індексованими переглядами може бути. Як я вже згадував у коментарі до іншого питання, посилання на перегляд у запиті розширюється перед оптимізацією, тому оптимізатор не знає, що ви написали запит проти перегляду в першу чергу - він бачить лише розширене дерево (як би вид був укладений).

"Гарний достатній план" означає, що оптимізатор знайшов гідний план і рано зупинився на фазі розвідки. "TimeOut" означає, що він перевищив кількість кроків оптимізації, які він встановив як "бюджет" на початку поточної фази.

Бюджет встановлюється на основі вартості найкращого плану, знайденого на попередньому етапі. При такому недорожному запиті (0,05) кількість бюджетних рухів буде зовсім невеликою, і швидко вичерпається регулярною трансформацією, враховуючи кількість приєднань, що беруть участь у вашому вибірковому запиті (наприклад, існує безліч способів переставити внутрішні з'єднання) .

Якщо вам цікаво дізнатися більше про те, чому збігання індексованого перегляду коштує дорого, і тому залишається для наступних етапів оптимізації та / або розглядається лише для більш дорогих запитів, є два дослідницькі документи Microsoft на цю тему тут (pdf) та тут (citeseer ).

Ще один важливий фактор полягає в тому, що відповідність індексованого перегляду недоступна на етапі оптимізації 0 (обробка транзакцій).

Подальше читання:

Індексовані перегляди та статистика

* і доступна лише у Enterprise Edition (або еквівалент)

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.