Почему оптимизатор запросов полностью игнорирует индексированные индексы представления?

SQL Fiddle:http://sqlfiddle.com#!6 / d4496 / 1 (данные предварительно генерируются для ваших экспериментов)

есть очевидная таблица:

CREATE TABLE Entity 
(
  ID int,
  Classificator1ID int,
  Classificator2ID int,
  Classificator3ID int,
  Classificator4ID int,
  Classificator5ID int
);

вид :

CREATE VIEW dbo.EntityView (ID, Code1, Code2, Code3, Code4, Code5) 
WITH SCHEMABINDING

где объекты поля Classificator1ID..Classificator5ID решил значений классификаторов Код1..Code5

и есть много индексов на этом представлении:

CREATE UNIQUE CLUSTERED INDEX [IXUC_EntityView$ID] ON EntityView
  ([ID]);
CREATE UNIQUE NONCLUSTERED  INDEX [IXU_EntityView$ID$include$ALL] ON EntityView
  ([ID]) INCLUDE (Code1, Code2, Code3, Code4,  Code5);
CREATE UNIQUE NONCLUSTERED  INDEX [IXU_EntityView$ALL] ON EntityView
  ([ID],Code1, Code2, Code3, Code4,  Code5);  
CREATE UNIQUE NONCLUSTERED  INDEX [IXU_EntityView$ID$Code1] ON EntityView
  ([ID],Code1);
CREATE UNIQUE NONCLUSTERED  INDEX [IXU_EntityView$ID$include$Code1] ON EntityView
  ([ID])INCLUDE (Code1);
CREATE NONCLUSTERED  INDEX [IX_EntityView$Code1] ON EntityView
  (Code1);
CREATE NONCLUSTERED  INDEX [IX_EntityView$Code1$include$ID] ON EntityView
  (Code1) INCLUDE (ID);

но QO никогда не использовать их! Попробуйте это:

SELECT * FROM EntityView;

SELECT ID, Code1 FROM EntityView;

SELECT ID, Code1, Code2, Code3, Code4, Code5 FROM EntityView;

SELECT ID, Code1, Code2, Code3, Code4, Code5 FROM EntityView WHERE ID=1;

SELECT ID, Code1 FROM EntityView Where Code1 like 'NR%';

Почему? И особенно что не так с индексами "include"? индекс создан, имеет все поля и все еще не используется...

добавлено: ЭТО ПРОСТО ТЕСТ! Пожалуйста, не будь таким злым и не толкать меня, чтобы проанализировать эти показатели проблемы maitinence.

в моем реальном проекте я не могу объяснить, почему QO игнорирует индексированные представления (очень-очень полезные индексированные представления). Но иногда я вижу, как он использует их в других местах. Я создал этот фрагмент БД для экспериментов с индексными формулами, но, возможно, я нужно сделать что-то еще: как-то настроить statistcs ?

3 ответов


запуск на 2012 Developer Edition unhinted запрос оценивается примерно в 8 раз больше, чем намекнул запрос

enter image description here

в то время как фактор 8 может звучать много, ваши данные примера довольно малы, и стоимость выбора непосредственно из базовых таблиц 0.0267122 vs 0.003293 для сметной стоимости из представления.

Пол Уайт объясняет в ответ здесь Это автоматическое индексированное сопоставление представлений даже не будет считается, если сначала найден достаточно низкий план.

искусственно натыкаясь на расходы для всех таблиц, участвующих

UPDATE STATISTICS Classificator1 WITH ROWCOUNT = 60000000, PAGECOUNT = 10000000 
UPDATE STATISTICS Classificator2 WITH ROWCOUNT = 60000000, PAGECOUNT = 10000000 
UPDATE STATISTICS Classificator3 WITH ROWCOUNT = 60000000, PAGECOUNT = 10000000 
UPDATE STATISTICS Classificator4 WITH ROWCOUNT = 60000000, PAGECOUNT = 10000000 
UPDATE STATISTICS Classificator5 WITH ROWCOUNT = 60000000, PAGECOUNT = 10000000 
UPDATE STATISTICS Entity         WITH ROWCOUNT = 60000000, PAGECOUNT = 10000000 

увеличивает стоимость базового плана таблицы до 29122.6

теперь вы должны увидеть сопоставление представления (в выпусках Enterprise/Developer/Evaluation), если вы явно не намекаете на иное.

SELECT * FROM EntityView;

SELECT * FROM EntityView OPTION (EXPAND VIEWS) 

enter image description here


tl; dr ответ: если вы не укажете NOEXPAND, оптимизатор запросов понятия не имеет, что вы отправляете простой выбор из представления. Он должен был бы соответствовать расширению вашего запроса (что все, что он видит) с некоторым индексом представления. Вероятно, не будет беспокоиться, когда это пятистороннее соединение с кучей слепков.

просмотр индекса, соответствующего запросу, является сложной проблемой, и я считаю, что ваше представление слишком сложно для механизма запросов, чтобы соответствовать индексу. Считайте это одним из ваших запросы:

SELECT ID, Code1 FROM EntityView Where Code1 > 'NR%';

для вас очевидно, что это может использовать индекс представления, но это не запрос, который видит механизм запросов. Представления автоматически расширяются, если вы не указываете NOEXPAND, поэтому это то, что идет в механизм запросов:

SELECT ID, Code1 FROM (
    SELECT e.ID, 'NR'+CAST(c1.CODE as nvarchar(11)) as Code1, 'NR'+CAST(c2.CODE as nvarchar(11)) as Code2, 'NR'+CAST(c3.CODE as nvarchar(11)) as Code3, 'NR'+CAST(c4.CODE as nvarchar(11)) as Code4, 'NR'+CAST(c5.CODE as nvarchar(11)) as Code5
    FROM dbo.Entity e
        inner join  dbo.Classificator1 c1 on e.ID = c1.ID
        inner join  dbo.Classificator2 c2 on e.ID = c2.ID
        inner join  dbo.Classificator3 c3 on e.ID = c3.ID
        inner join  dbo.Classificator4 c4 on e.ID = c4.ID
        inner join  dbo.Classificator5 c5 on e.ID = c5.ID;
) AS V;

механизм запросов видит этот сложный запрос, и у него есть информация (но, вероятно, не SQL определений представления), которые описывают определенные индексы представления. Учитывая, что этот запрос и индексы представления имеют несколько соединения и приведения, сопоставление-тяжелая работа.

имейте в виду, что вы знаете, что соединения и совпадения идентичны в этом запросе и индексах представления, но процессор запросов этого не знает. Он обрабатывает этот запрос так же, как если бы он объединил пять копий Classificator3 или если один из столбцов был " NQ " +CAST(c2.Код как varchar(12)). Сопоставитель индекса представления (предполагая, что он попытался сопоставить этот сложный запрос) должен был бы сопоставить каждую деталь этого запроса с деталями просмотреть индексы таблиц.

механизм запросов имеет своей целью #1 выяснить способ эффективного выполнения запроса. Вероятно, он не предназначен для того, чтобы тратить много времени на сопоставление каждой детали пятистороннего соединения и приведения к индексу представления.

Если бы мне пришлось угадать, я подозреваю, что сопоставитель индекса представления видит, что результирующие столбцы запроса даже не являются столбцами какой-либо базовой таблицы (из-за приведения) и просто ничего не пытается. добавил: я ошибаюсь. Я просто попробовал предложение Мартина об обновлении статистики, чтобы сделать запрос дорогим, и индекс представления был сопоставлен для некоторых из этих запросов без NOEXPAND. Смотритель умнее, чем я думал! Поэтому проблема заключается в том, что view matcher, вероятно, пытается сложнее сопоставить сложный запрос, если его стоимость очень высока.

используйте подсказку NOEXPAND вместо того, чтобы ожидать, что механизм запросов сможет выяснить, что соответствует здесь. NOEXPAND абсолютно ваш друг, потому что тогда механизм запросов получает видеть

SELECT ID, Code1 FROM EntityView Where Code1 > 'NR%';

и тогда сразу становится очевидным для сопоставления индексов представления, что есть полезный индекс.

(Примечание: ваш код скрипки SQL имеет все 5 ссылок внешнего ключа на одну и ту же таблицу, что, вероятно, не то, что вы хотите.)


используйте подсказку WITH (NOExpand), если вы находитесь в SQL Server Enterprise

ваш запрос будет SELECT * FROM EntityView with (noexpand)