Как я могу ускорить это индексированное представление? - PullRequest
12 голосов
/ 17 июня 2009

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

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

Схема

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

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 с лишним секунд. WTF? Это должно быть .. в основном мгновенно!

Запрос 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 все испортил? Я думал, что, поскольку у меня есть index'd это представление, оно будет реализовано. Таким образом, ему не нужно будет вычислять этот строковый столбец.

Вот скриншот плана запроса, если это поможет: - 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

Спасибо всем за помощь в решении этой проблемы:)

Ответы [ 6 ]

18 голосов
/ 17 июня 2009

Какая редакция 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 и указано WITH (NOEXPAND) или WITH (NOEXPAND, INDEX (index_value [, ... n])). *

4 голосов
/ 17 июня 2009

Я вижу знак @ в коде запроса в вашем плане выполнения. Включена строковая переменная.

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


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

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

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

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

0 голосов
/ 17 июня 2009

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

0 голосов
/ 17 июня 2009

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

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

Микширование в UDF-логике запутывает вещи еще больше.

0 голосов
/ 17 июня 2009

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

0 голосов
/ 17 июня 2009

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...