Создание индексированных представлений
Область применения: SQL Server
База данных SQL Azure Управляемый экземпляр SQL Azure
В этой статье описывается, как создавать индексы в представлении. Первым индексом, создаваемым для представления, должен быть уникальный кластеризованный индекс. После создания уникального кластеризованного индекса могут быть созданы некластеризованные индексы. Создание уникального кластеризованного индекса в представлении повышает производительность запросов, так как представление хранится в базе данных таким же образом, как таблица с кластеризованным индексом сохраняется. Оптимизатор запросов может использовать индексированные представления для ускорения выполнения запроса. Оптимизатор может рассматривать представление для подстановки, даже если оно не указано в запросе.
Шаги
Чтобы создать индексированное представление, нужно выполнить следующие шаги. Точность при их выполнении критически важна для успешной реализации индексированного представления.
- Проверьте правильность
SET
параметров для всех существующих таблиц, на которые будут ссылаться в представлении. - Убедитесь, что
SET
параметры сеанса заданы правильно перед созданием таблиц и представления. - Проверьте, что определение представления детерминировано.
- Убедитесь, что у базовой таблицы тот же владелец, что и у представления.
- Создайте представление с помощью параметра
WITH SCHEMABINDING
. - Создайте уникальный кластеризованный индекс для представления.
При выполнении UPDATE
, DELETE
или INSERT
операций (язык манипуляции данными, или DML) в таблице, на которую ссылается большое количество индексированных представлений, или меньше, но более сложных индексированных представлений, необходимо также обновить эти индексированные представления. В результате производительность запросов DML может значительно снизиться или в некоторых случаях план запроса даже не может быть создан.
В таких ситуациях протестируйте запросы DML перед использованием в рабочей среде, проанализируйте план запроса и настройте или упростите инструкцию DML.
Обязательные параметры SET для индексированных представлений
Вычисление одного выражения может привести к разным результатам в ядре СУБД, если при выполнении запроса активны различные параметры SET
. Например, после SET
задания CONCAT_NULL_YIELDS_NULL
параметра ON
выражение 'abc' + NULL
возвращает значение NULL
. Однако после установки CONCAT_NULL_YIELDS_NULL
на OFF
то же самое выражение дает abc
.
Чтобы убедиться, что представления можно поддерживать правильно и возвращать согласованные результаты, индексированные представления требуют фиксированных значений для нескольких SET
вариантов. Параметры SET
в следующей таблице должны иметь значения, отображаемые в Required value
столбце при каждом возникновении следующих условий:
- Создано представление и последующие индексы на представлении.
- Базовые таблицы, на которые ссылается представление в момент создания представления.
- При выполнении любой операции вставки, обновления или удаления в любой таблице, которая участвует в индексированном представлении. Это требование охватывает такие операции, как массовое копирование, репликация и распределенные запросы.
- Индексированное представление используется оптимизатором запросов для создания плана запроса.
Параметры SET | Обязательное значение | Значение сервера по умолчанию | По умолчанию. Значение OLE DB и ODBC |
По умолчанию. Значение DB-Library |
---|---|---|---|---|
ANSI_NULLS |
ON |
ON |
ON |
OFF |
ANSI_PADDING |
ON |
ON |
ON |
OFF |
ANSI_WARNINGS
1 |
ON |
ON |
ON |
OFF |
ARITHABORT |
ON |
ON |
OFF |
OFF |
CONCAT_NULL_YIELDS_NULL |
ON |
ON |
ON |
OFF |
NUMERIC_ROUNDABORT |
OFF |
OFF |
OFF |
OFF |
QUOTED_IDENTIFIER |
ON |
ON |
ON |
OFF |
1 Установка ANSI_WARNINGS
в ON
неявно устанавливает ARITHABORT
в ON
.
Если вы используете подключение к СЕРВЕРУ OLE DB или ODBC, то единственным значением, которое необходимо изменить, является ARITHABORT
параметр. Все значения библиотеки DB должны быть правильно заданы на уровне сервера с помощью sp_configure
или из приложения с помощью SET
команды.
Внимание
Настоятельно рекомендуется задать параметр пользователя ARITHABORT
на уровне ON
сервера, как только первое индексированное представление или индекс вычисляемого столбца будет создано в какой-либо базе данных на сервере.
Требование к детерминированному представлению
Определение индексированного представления должно быть детерминированным. Представление является детерминированным, если все выражения в списке выбора, а также в WHERE
, GROUP BY
предложениях являются детерминированными. Детерминированные выражения всегда возвращают тот же результат, когда они вычисляются с определенным набором входных значений. Только детерминированные функции могут использоваться в детерминированных выражениях. Например, функция DATEADD
детерминирована, так как всегда возвращает один и тот же результат для любого заданного набора значений аргументов трех ее параметров.
GETDATE
не является детерминированным, поскольку он всегда вызывается с одним и тем же аргументом, но возвращаемое им значение изменяется при каждом выполнении.
Чтобы определить, является ли столбец представления детерминированным, используйте IsDeterministic
свойство функции COLUMNPROPERTY . Чтобы определить, является ли точным детерминированный столбец в представлении с привязкой схемы, используйте свойство IsPrecise
функции COLUMNPROPERTY
.
COLUMNPROPERTY
возвращает 1
, если TRUE
, 0
, если FALSE
, и NULL
для недопустимых входных данных. Это означает, что столбец не является детерминированным или не точным.
Даже если выражение детерминировано, если оно содержит выражения с плавающей запятой, то точный результат зависит от архитектуры процессора или версии микрокода. Для сохранения целостности данных такие выражения могут быть только неключевыми столбцами индексированных представлений. Детерминированные выражения, не содержащие выражения с плавающей запятой, называются точными. Только точные детерминированные выражения могут содержаться в ключевых столбцах и предложениях WHERE
или GROUP BY
индексированных представлений.
Дополнительные требования
В дополнение к параметрам SET
и требованиям детерминированных функций также должны быть выполнены следующие требования.
Пользователь, выполняющий инструкцию
CREATE INDEX
, должен быть владельцем представления.При создании индекса необходимо установить параметр индекса
IGNORE_DUP_KEY
в значениеOFF
(по умолчанию).Таблицы должны упоминаться по двухсоставным именам,
<schema>.<tablename>
, в определении представления.Определяемые пользователем функции, на которые ссылается представление, должны быть созданы с параметром
WITH SCHEMABINDING
.Все определяемые пользователем функции, на которые ссылаются в представлении, должны ссылаться двумя именами частей.
<schema>.<function>
Свойство доступа к данным пользовательской функции должно быть установлено в значение
NO SQL
, а свойство внешнего доступа — вNO
.Функции среды выполнения CLR могут отображаться в списке выбора представления, но не могут быть частью определения кластеризованного ключа индекса. Функции CLR не могут появляться в предложении
WHERE
представления или предложенииON
операцииJOIN
в представлении.Функции и методы CLR определяемого пользователем типа данных, используемые в определении представления, должны иметь свойства, установленные так, как показано в следующей таблице.
Свойство Примечание. ДЕТЕРМИНИРОВАННЫЙ = ИСТИНА Должно быть объявлено явно в качестве атрибута метода Microsoft .NET Framework. PRECISE = ИСТИНА Должно быть объявлено явно в качестве атрибута метода .NET Framework. Доступ к данным = NO SQL Определяется путем задания атрибута DataAccess
значениемDataAccessKind.None
и атрибутаSystemDataAccess
значениемSystemDataAccessKind.None
.ВНЕШНИЙ ДОСТУП = НЕТ Для процедур CLR значением свойства по умолчанию является NO. Представление должно быть создано с параметром
WITH SCHEMABINDING
.В представлении допустимы ссылки только на базовые таблицы той же самой базы данных. Представление не может ссылаться на другие представления.
Если присутствует предложение
GROUP BY
, определение VIEW должно содержатьCOUNT_BIG(*)
и не должно содержатьHAVING
. Эти ограничения применимы только к определению индексированного представленияGROUP BY
. Запрос может использовать индексированное представление в плане выполнения, даже если оно не удовлетворяет этимGROUP BY
ограничениям.Если определение представления содержит предложение
GROUP BY
, ключ уникального кластеризованного индекса может включать только столбцы, указанные в предложенииGROUP BY
.Инструкция
SELECT
в определении представления не должна содержать следующий синтаксис Transact-SQL:Функция Transact-SQL Возможные альтернативные варианты COUNT
Используйте COUNT_BIG
ROWSET
функции (OPENDATASOURCE
,OPENQUERY
,OPENROWSET
, иOPENXML
)Арифметическое среднее ( AVG
)Использование COUNT_BIG
иSUM
в качестве отдельных столбцовСтатистические агрегатные функции ( STDEV
,STDEVP
,VAR
иVARP
)Функция SUM
, ссылающаяся на выражение, допускающее значение NULLИспользуйте ISNULL
внутриSUM()
, чтобы сделать выражение не допускающим значение NULLДругие агрегатные функции ( MIN
,MAX
,CHECKSUM_AGG
иSTRING_AGG
)Определяемые пользователем агрегатные функции (SQL CLR) Предложение SELECT Элемент Transact-SQL Возможная альтернатива WITH cte AS
Распространенные табличные выражения (CTE) WITH
SELECT
Подзапросы SELECT
SELECT [ <table>. ] *
Явно указать названия столбцов SELECT
SELECT DISTINCT
Используйте GROUP BY
SELECT
SELECT TOP
SELECT
Предложение OVER
, включающее ранжирующие функции или агрегатные оконные функцииFROM
LEFT OUTER JOIN
FROM
RIGHT OUTER JOIN
FROM
FULL OUTER JOIN
FROM
OUTER APPLY
FROM
CROSS APPLY
FROM
Производные табличные выражения (т. е. использование SELECT
в предложенииFROM
)FROM
Самосоединения FROM
Табличные переменные FROM
Встроенная табличная функция FROM
Функция с табличным значением с несколькими операторами FROM
PIVOT
,UNPIVOT
FROM
TABLESAMPLE
FROM
FOR SYSTEM_TIME
Выполнить запрос к таблице истории изменяющихся данных напрямую WHERE
Полнотекстовые предикаты ( CONTAINS
, ,FREETEXT
CONTAINSTABLE
,FREETEXTTABLE
)GROUP BY
Операторы CUBE
,ROLLUP
илиGROUPING SETS
Определите отдельные индексированные представления для каждого сочетания столбцов GROUP BY
GROUP BY
HAVING
Операторы Set UNION
,UNION ALL
,EXCEPT
,INTERSECT
Использование OR
,AND NOT
иAND
в предложенииWHERE
соответственноORDER BY
ORDER BY
ORDER BY
OFFSET
Тип исходного столбца Возможная альтернатива Устаревшие типы столбцов больших значений (текст, ntext и изображение) Перенос столбцов в varchar(max), nvarchar(max), а также varbinary(max) соответственно. Столбцы XML или столбцы FILESTREAM float1 столбец в ключе индекса Наборы разреженных столбцов 1 Индексированное представление может содержать столбцы с плавающей запятой . Однако такие столбцы нельзя включить в кластеризованный ключ индекса.
Внимание
Индексированные представления не поддерживаются поверх темпоральных запросов (запросов, использующих
FOR SYSTEM_TIME
предложение).
Рекомендации для datetime и smalldatetime
При ссылке на строковые литералы datetime и smalldatetime в индексированных представлениях рекомендуется явно преобразовывать литерал в нужный тип даты при помощи детерминированного стиля формата даты. Список детерминированных стилей форматирования даты см. в разделе CAST и CONVERT. Дополнительные сведения о детерминированных и недетерминированных выражениях см. в разделе Замечания.
Выражения, включающие неявные преобразования символьных строк в типы datetime или smalldatetime , считаются недетерминированными. Дополнительные сведения см. в статье Недетерминированное преобразование литеральных строковых дат в значения DATE.
Вопросы производительности при индексированных представлениях
При выполнении DML (например, UPDATE
, DELETE
или INSERT
) на таблице, на которую ссылается большое количество индексированных представлений, или немного сложных индексированных представлений, эти индексированные представления также необходимо обновить во время выполнения DML. В результате производительность запросов DML может значительно снизиться или в некоторых случаях план запроса даже не может быть создан. В таких ситуациях протестируйте запросы DML перед использованием в рабочей среде, проанализируйте план запроса и настройте или упростите инструкцию DML.
Чтобы предотвратить использование ядром СУБД индексированных представлений, добавьте указание OPTION (EXPAND VIEWS) в запрос. Кроме того, если какие-либо из перечисленных параметров заданы неправильно, этот параметр запрещает оптимизатору использовать индексы в представлениях. Дополнительные сведения о подсказке OPTION (EXPAND VIEWS)
см. в разделе SELECT.
Дополнительные рекомендации
Параметр
large_value_types_out_of_row
параметра столбцов в индексном представлении наследуется от параметра соответствующего столбца в базовой таблице. Это значение задается с помощью sp_tableoption. Параметр по умолчанию для столбцов, сформированных из выражений0
. Это означает, что типы больших значений хранятся в строке данных.Индексированные представления могут создаваться на секционированной таблице и сами могут быть секционированными.
При удалении представления удаляются также и все его индексы. При удалении кластеризованного индекса из представления удаляются все некластеризованные индексы и автоматически созданные статистики. Статистики, созданные пользователем, сохраняются. Некластеризованные индексы могут удаляться по отдельности. При удалении кластеризованного индекса представления удаляется сохраненный результирующий набор, и оптимизатор снова начинает работать с ним, как с обычным представлением.
Индексы таблиц и представлений могут быть отключены. При отключении кластеризованного индекса таблицы индексы представлений, связанных с ней, также отключаются.
Разрешения
Чтобы создать представление, пользователю необходимо сохранить CREATE VIEW
разрешение в базе данных и ALTER
разрешение на схему, в которой создается представление. Если базовая таблица находится в другой схеме, REFERENCES
разрешение на таблицу требуется как минимум. Если пользователь, создающий индекс, отличается от пользователей, создавших представление, для создания индекса требуется только разрешение ALTER
на представление (это покрывается ALTER
в схеме).
Индексы можно создавать только в представлениях с тем же владельцем, что и в указанной таблице или таблицах. Эта концепция также называется нетронутой цепочкой владения между представлением и таблицами. Как правило, если таблица и представление находятся в одной схеме, то один и тот же владелец схемы применяется ко всем объектам в схеме. Поэтому можно создать представление и не быть владельцем представления. С другой стороны, также возможно, что отдельные объекты в схеме имеют разных явных владельцев. В столбце principal_id
в sys.tables
содержится значение, если владелец отличается от владельца схемы.
Создание индексированного представления: пример для T-SQL
В следующем примере создается представление и индекс на этом представлении в базе данных AdventureWorks
.
--Set the options to support indexed views.
SET NUMERIC_ROUNDABORT OFF;
SET ANSI_PADDING,
ANSI_WARNINGS,
CONCAT_NULL_YIELDS_NULL,
ARITHABORT,
QUOTED_IDENTIFIER,
ANSI_NULLS ON;
--Create view with SCHEMABINDING.
IF OBJECT_ID('Sales.vOrders', 'view') IS NOT NULL
DROP VIEW Sales.vOrders;
GO
CREATE VIEW Sales.vOrders
WITH SCHEMABINDING
AS
SELECT SUM(UnitPrice * OrderQty * (1.00 - UnitPriceDiscount)) AS Revenue,
OrderDate,
ProductID,
COUNT_BIG(*) AS COUNT
FROM Sales.SalesOrderDetail AS od,
Sales.SalesOrderHeader AS o
WHERE od.SalesOrderID = o.SalesOrderID
GROUP BY OrderDate,
ProductID;
GO
--Create an index on the view.
CREATE UNIQUE CLUSTERED INDEX IDX_V1 ON Sales.vOrders (
OrderDate,
ProductID
);
GO
В следующих двух запросах показано, как можно использовать индексированное представление, даже если представление не указано в предложении FROM
.
--This query can use the indexed view even though the view is
--not specified in the FROM clause.
SELECT SUM(UnitPrice * OrderQty * (1.00 - UnitPriceDiscount)) AS Rev,
OrderDate,
ProductID
FROM Sales.SalesOrderDetail AS od
INNER JOIN Sales.SalesOrderHeader AS o
ON od.SalesOrderID = o.SalesOrderID
AND o.OrderDate >= CONVERT(DATETIME, '05/01/2012', 101)
WHERE od.ProductID BETWEEN 700
AND 800
GROUP BY OrderDate,
ProductID
ORDER BY Rev DESC;
GO
--This query will also use the above indexed view.
SELECT OrderDate,
SUM(UnitPrice * OrderQty * (1.00 - UnitPriceDiscount)) AS Rev
FROM Sales.SalesOrderDetail AS od
INNER JOIN Sales.SalesOrderHeader AS o
ON od.SalesOrderID = o.SalesOrderID
AND o.OrderDate >= CONVERT(DATETIME, '03/01/2012', 101)
AND o.OrderDate < CONVERT(DATETIME, '04/01/2012', 101)
GROUP BY OrderDate
ORDER BY OrderDate ASC;
Наконец, в этом примере показано выполнение запросов непосредственно из индексированного представления. Автоматическое использование индексированного представления оптимизатором запросов поддерживается только в определенных выпусках SQL Server. В выпуске SQL Server Standard необходимо использовать NOEXPAND
подсказку запроса для обращения к индексированному представлению напрямую. База данных SQL Azure и Управляемый экземпляр SQL Azure поддерживают автоматическое использование индексированных представлений без указания подсказки NOEXPAND
. Дополнительные сведения см. в статье Указания по таблицам (Transact-SQL).
--This query uses the indexed view directly, on Enterprise edition.
SELECT OrderDate, Revenue
FROM Sales.vOrders
WHERE OrderDate >= CONVERT(DATETIME, '03/01/2012', 101)
AND OrderDate < CONVERT(DATETIME, '04/01/2012', 101)
ORDER BY OrderDate ASC;
--This query uses the indexed view directly, with the NOEXPAND hint.
SELECT OrderDate, Revenue
FROM Sales.vOrders WITH (NOEXPAND)
WHERE OrderDate >= CONVERT(DATETIME, '03/01/2012', 101)
AND OrderDate < CONVERT(DATETIME, '04/01/2012', 101)
ORDER BY OrderDate ASC;
Дополнительные сведения см. в разделе CREATE VIEW.