Использование индексированных представлений для агрегатов - слишком хорошо, чтобы быть правдой?


28

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

SELECT
    f.IsFoo,
    COUNT(*) AS WidgetCount
FROM Widgets AS w
JOIN Flags AS f
    ON f.FlagId = w.FlagId
WHERE w.Date >= @startDate
GROUP BY f.IsFoo

Производительность не ужасная, но может быть относительно вялой (возможно, 10 секунд на холодном кэше).

Недавно я обнаружил, что могу использовать GROUP BYв индексированных представлениях, и поэтому попробовал нечто похожее на следующее

CREATE VIEW TestView
WITH SCHEMABINDING
AS
    SELECT
        Date,
        FlagId,
        COUNT_BIG(*) AS WidgetCount
    FROM Widgets
    GROUP BY Date, FlagId;
GO

CREATE UNIQUE CLUSTERED INDEX PK_TestView ON TestView
(
    Date,
    FlagId
);

В результате производительность моего первого запроса теперь <100 мс, а результирующее представление и индекс <100 тыс. (Хотя количество строк у нас большое, диапазон дат и идентификаторов флагов означает, что это представление содержит только 1000-2000 строк).

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

Мне это кажется слишком хорошим, чтобы быть правдой - не так ли? С чем мне следует быть осторожным при использовании индексированных представлений таким образом?


2
Можете ли вы переписать свои сценарии, чтобы они действительно были действительными SQL? Вы SELECTи CREATE VIEWсценарии не правы, так как я считаю, что ваш CREATE INDEXсценарий.
Марк Синкинсон

2
@MarkSinkinson Извинения, оказывается, что попытка написать допустимый SQL для мнимых таблиц трудна
Джастин

Часть «слишком хорошая, чтобы быть правдой» для меня возникла, когда мне потребовались более продвинутые представления, например, содержащие MAX, собственные или внешние объединения, или индексирование представления, которое само ссылается на другое представление - все это, по крайней мере, в SQL Server, не является таковым. разрешено docs.microsoft.com/en-us/sql/relational-databases/views/… . Таким образом, я всегда становлюсь чрезмерно амбициозным, а затем вынужден все уменьшать. Но для более простых агрегаций они действительно хороши - поддерживается даже SUM.
Simon_Weaver

Ответы:


29

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

Это не слишком хорошо, чтобы быть правдой. Вы используете индексированные представления именно так, как они должны были использоваться - или, по крайней мере, один из наиболее эффективных способов: платить за будущие агрегаты запросов во время записи. Это работает лучше всего, когда результат намного меньше исходного и, конечно, когда агрегаты запрашиваются чаще, чем обновляются базовые данные (чаще встречается в DW, чем в OLTP, как правило).

К сожалению, многие люди думают, что индексирование представления - это волшебство - индекс не сделает все представления более эффективными, особенно представления, которые просто объединяют таблицы и / или производят такое же количество строк, что и источник (или даже умножают). В этих случаях ввод-вывод в представлении такой же или даже хуже, чем в исходном запросе, не только потому, что есть такие же или более строк, но часто они также хранят и материализуют больше столбцов. Таким образом, материализация их заранее не дает никакой выгоды, поскольку - даже с твердотельными накопителями - ввод-вывод, обработка и рендеринг сети и клиента по-прежнему остаются основными узкими местами при возврате больших наборов результатов клиенту. Экономия, которую вы получаете, избегая объединения во время выполнения, просто не поддается измерению по сравнению со всеми другими ресурсами, которые вы все еще используете.

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

Черт возьми, я собирался вести блог на эту тему.


19

Ответы Аарона хорошо охватили этот вопрос. Две вещи, которые нужно добавить:

  1. Агрегированные индексированные представления могут привести к конфликту между строками и тупикам. Обычно две вставки не блокируются (за исключением довольно редких условий, таких как повышение блокировки или столкновение хэшей блокировки). Но если обе вставки обращаются к одной и той же группе в представлении, они будут бороться. То же самое относится ко всему, что берет блокировки (DML, подсказки блокировки).
  2. Индексированные представления, которые не агрегируются, также могут быть полезны. Они позволяют индексировать столбцы из нескольких таблиц. Таким образом, вы можете эффективно фильтровать одну таблицу и упорядочивать ее по столбцу из объединенной таблицы. Этот шаблон может преобразовать соединение с полной таблицей в крошечные запросы постоянного времени.

Я использовал как агрегирование, так и объединение представлений с исключительной выгодой

В целом ваш вариант использования кажется идеальным. Индексированные представления - это метод, который недостаточно используется.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.