Как я могу ускорить это индексированное представление?

StackOverflow https://stackoverflow.com/questions/1004944

Вопрос

У меня есть простое индексированное представление.Когда я делаю запрос к нему, это происходит довольно медленно.Сначала я покажу вам схему и индексы.Затем простые запросы.Наконец, скренирование плана запроса.

Обновить:Доказательство решения приведено в нижней части этого поста.

Схема

Вот как это выглядит :-

CREATE view [dbo].[PostsCleanSubjectView] with SCHEMABINDING AS
    SELECT PostId, PostTypeId, 
        [dbo].[ToUriCleanText]([Subject]) AS CleanedSubject
    FROM [dbo].[Posts]

Мой udf ToUriCleanText просто заменяет различные символы пустым символом.Например.заменяет все символы '#' на ".

Затем я добавил к этому два индекса :-

Индексы

Индекс первичного ключа (т.е.Кластеризованный индекс)

CREATE UNIQUE CLUSTERED INDEX [PK_PostCleanSubjectView] ON 
    [dbo].[PostsCleanSubjectView] 
(
    [PostId] ASC
)
WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, 
      SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF,
      ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
GO

И Некластеризованный индекс

CREATE NONCLUSTERED INDEX [IX_PostCleanSubjectView_PostTypeId_Subject] ON 
    [dbo].[PostsCleanSubjectView] 
(
    [CleanedSubject] ASC,
    [PostTypeId] ASC
)
WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, 
      SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF,
      ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
GO

Теперь в нем около 25 тысяч строк.Вообще ничего особенного.

Когда я выполняю следующие запросы, они оба занимают около 4 с лишним секунд.ВТФ?Так и должно быть..практически мгновенно!

Запрос 1

SELECT a.PostId
FROM PostsCleanSubjectView a 
WHERE a.CleanedSubject = 'Just-out-of-town'

Запрос 2 (добавлен еще один элемент предложения where)

SELECT a.PostId
FROM PostsCleanSubjectView a 
WHERE a.CleanedSubject = 'Just-out-of-town' AND a.PostTypeId = 1

Что я сделал не так?Неужели UDF все испортило?Я думал, что, поскольку я проиндексировал это представление, оно будет материализовано.Таким образом, ему не пришлось бы вычислять этот столбец string.

Вот скриншот плана запроса, если это поможет :- alt text

Кроме того, обратите внимание на индекс, который он использует?Почему он использует этот индекс?

Этот индекс таков...

CREATE NONCLUSTERED INDEX [IX_Posts_PostTypeId_Subject] ON [dbo].[Posts] 
(
    [PostTypeId] ASC,
    [Subject] ASC
)
WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, 
      SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, 
      ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
GO

Так что да, ребята, есть какие-нибудь идеи?

Обновление 1:Добавлена схема для udf.

CREATE FUNCTION [dbo].[ToUriCleanText]
(
    @Subject NVARCHAR(300)
)
RETURNS NVARCHAR(350) WITH SCHEMABINDING
AS 
BEGIN
   <snip>
   // Nothing insteresting in here. 
   //Just lots of SET @foo = REPLACE(@foo, '$', ''), etc.
END

Обновление 2:Решение

Да, это было потому, что я не использовал индекс в представлении и должен был вручную убедиться, что я не расширял представление.Сервером является Sql Server 2008 Standard Edition.Полный ответ приведен ниже.Вот доказательство, WITH (NOEXPAND) alt text

Спасибо вам всем за то, что помогли мне решить эту проблему :)

Это было полезно?

Решение

Какая версия SQL Server?Я полагаю, что только Enterprise и Developer Edition будут использовать индексированные представления автоматически, в то время как остальные поддерживают это с помощью подсказок к запросам.

SELECT a.PostId
FROM PostsCleanSubjectView a WITH (NOEXPAND)
WHERE a.CleanedSubject = 'Just-out-of-town' AND a.PostTypeId = 1

От Подсказки по запросам (Transact SQL) в MSDN:

Индексированное представление не расширяется, только если на представление дана прямая ссылка в части запроса SELECT и указано С ПОМОЩЬЮ (NOEXPAND) или С ПОМОЩЬЮ (NOEXPAND, INDEX( index_value [ ,...n ] ) ).

Другие советы

Я вижу знак @ в коде запроса в вашем плане выполнения.Здесь задействована строковая переменная.

Sql Server имеет НЕПРИЯТНОЕ поведение, если тип строковой переменной не соответствует типу столбца string в индексе.Sql Server сделает это ... преобразовать весь столбец целиком для этого типа выполните быстрый поиск, а затем выбросьте преобразованный индекс, чтобы он мог выполнить все это снова при следующем запросе.


Саймон понял это, но вот еще одна полезная деталь: http://msdn.microsoft.com/en-us/library/ms187373.aspx

Если запрос содержит ссылки на столбцы, которые присутствуют как в индексированном представлении, так и в базовых таблицах, и оптимизатор запросов определяет, что использование индексированного представления обеспечивает наилучший метод выполнения запроса, оптимизатор запросов использует индекс в представлении.Эта функция вызывается соответствие индексированному виду, и поддерживается только в версиях SQL Server Enterprise и Developer.

Однако, чтобы оптимизатор рассмотрел индексированные представления для сопоставления или использовал индексированное представление, на которое ссылается подсказка NOEXPAND, для следующих параметров SET должно быть установлено значение ON:

Итак, что здесь происходит, так это то, что соответствие индексированному виду это не работает.Убедитесь, что вы используете корпоративные версии Sql Server или версии для разработчиков (вполне вероятно).Затем проверьте параметры вашего набора в соответствии со статьей.

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

Однако я не использовал SQL Enterprise, поэтому у меня не было возможности использовать индексированные представления.Предполагается ли, что индексированное представление способно индексировать детерминированные результаты UDF?

Я подозреваю, что он должен вызвать эту функцию для каждой строки, прежде чем сможет выполнить сравнение в вашем предложении where.Я бы раскрыл тему, запустил запрос, напрямую сверяясь с ней, и посмотрел, как сложатся времена.Обычно я сталкивался с большой медлительностью всякий раз, когда я изменяю значение с помощью функции, а затем использую его в предложении where...

Какую выгоду вы ищете, используя индексированное представление?Неужели невозможно правильно проиндексировать сами таблицы?Без веского обоснования вы усложняете работу и просите оптимизатора работать с большим количеством объектов базы данных с меньшей гибкостью.

Оценивали ли вы ту же логику запроса со стандартными индексами?

Смешивание в логике UDF еще больше запутывает ситуацию.

Если все, что вы хотите, это сохранить возвращаемое значение UDF, рассмотрите сохраняемый вычисляемый столбец, а не индексированное представление.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top