Как я могу ускорить это индексированное представление?
-
05-07-2019 - |
Вопрос
У меня есть простое индексированное представление.Когда я делаю запрос к нему, это происходит довольно медленно.Сначала я покажу вам схему и индексы.Затем простые запросы.Наконец, скренирование плана запроса.
Обновить:Доказательство решения приведено в нижней части этого поста.
Схема
Вот как это выглядит :-
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.
Вот скриншот плана запроса, если это поможет :-
Кроме того, обратите внимание на индекс, который он использует?Почему он использует этот индекс?
Этот индекс таков...
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)
Спасибо вам всем за то, что помогли мне решить эту проблему :)
Решение
Какая версия 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, рассмотрите сохраняемый вычисляемый столбец, а не индексированное представление.