Vytváření indexovaných zobrazení
platí pro:SQL Server
Azure SQL Database
azure SQL Managed Instance
Tento článek popisuje, jak vytvořit indexy v zobrazení. První index vytvořený v zobrazení musí být jedinečný clusterovaný index. Po vytvoření jedinečného clusterovaného indexu můžete vytvořit více neclusterovaných indexů. Vytvoření jedinečného clusterovaného indexu v zobrazení zlepšuje výkon dotazů, protože zobrazení je uložené v databázi stejným způsobem jako tabulka s clusterovaným indexem. Optimalizátor dotazů může k urychlení provádění dotazu použít indexovaná zobrazení. Zobrazení nemusí být v dotazu odkazováno, aby optimalizátor mohl toto zobrazení považovat za náhradní.
Schody
K vytvoření indexovaného zobrazení jsou potřeba následující kroky a jsou důležité pro úspěšnou implementaci indexovaného zobrazení:
- Ověřte správnost možností
SET
pro všechny existující tabulky, na které budou odkazovány v zobrazení. - Před vytvořením tabulek a zobrazení ověřte, že jsou správně nastavené možnosti
SET
pro relaci. - Ověřte, že definice zobrazení je deterministická.
- Ověřte, že základní tabulka má stejného vlastníka jako zobrazení.
- Vytvořte zobrazení pomocí možnosti
WITH SCHEMABINDING
. - Vytvořte jedinečný clusterovaný index v zobrazení.
Při provádění operací UPDATE
, DELETE
nebo INSERT
(Jazyk pro manipulaci s daty, nebo DML) na tabulce odkazované velkým počtem indexovaných zobrazení, nebo méně početnými, ale složitými indexovanými zobrazeními, musí být tato odkazovaná indexovaná zobrazení také aktualizována. Výsledkem je, že výkon dotazů DML se může výrazně snížit, nebo se v některých případech dokonce ani nepodaří vytvořit plán dotazu.
V takových scénářích otestujte dotazy DML před použitím v produkčním prostředí, analyzujte plán dotazu a vylaďte nebo zjednodušte příkaz DML.
Požadované možnosti SET pro indexovaná zobrazení
Vyhodnocení stejného výrazu může způsobit různé výsledky v databázovém stroji, pokud jsou při spuštění dotazu aktivní různé možnosti SET
. Například po nastavení možnosti SET
CONCAT_NULL_YIELDS_NULL
na ON
, výraz 'abc' + NULL
vrátí hodnotu NULL
. Po nastavení CONCAT_NULL_YIELDS_NULL
na OFF
však stejný výraz vytvoří abc
.
Aby bylo zajištěno správné udržování zobrazení a vrácení konzistentních výsledků, vyžadují indexovaná zobrazení pevné hodnoty pro několik možností SET
. Možnosti SET
v následující tabulce musí být nastaveny na hodnoty zobrazené ve sloupci Required value
vždy, když dojde k následujícím podmínkám:
- Vytvoří se zobrazení a následné indexy v zobrazení.
- Základní tabulky odkazované v zobrazení v okamžiku vytvoření zobrazení.
- Když se provede jakákoli operace vložení, aktualizace nebo odstranění v libovolné tabulce, která se účastní indexovaného zobrazení. Tento požadavek zahrnuje operace, jako jsou hromadné kopírování, replikace a distribuované dotazy.
- Indexované zobrazení používá optimalizátor dotazů k vytvoření plánu dotazu.
Možnosti SET | Požadovaná hodnota | Výchozí hodnota serveru | Výchozí Hodnota OLE DB a ODBC |
Výchozí hodnota 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 Nastavení ANSI_WARNINGS
ON
implicitně nastaví ARITHABORT
na ON
.
Pokud používáte připojení k serveru OLE DB nebo ODBC, jedinou hodnotou, kterou je nutné upravit, je nastavení ARITHABORT
. Všechny DB-Library hodnoty musí být správně nastaveny na úrovni serveru pomocí sp_configure
nebo z aplikace pomocí příkazu SET
.
Důležitý
Důrazně doporučujeme nastavit možnost ARITHABORT
uživatele na úrovni celého serveru (ON
), jakmile je na serveru v libovolné databázi vytvořeno první indexované zobrazení nebo index na vypočítaném sloupci.
Požadavek na deterministické zobrazení
Definice indexovaného zobrazení musí být deterministické. Zobrazení je deterministické, pokud jsou deterministické všechny výrazy v seznamu select a klauzule WHERE
a GROUP BY
. Deterministické výrazy vždy vrací stejný výsledek pokaždé, když se vyhodnotí konkrétní sadou vstupních hodnot. Deterministické funkce se mohou účastnit deterministických výrazů. Například DATEADD
funkce je deterministická, protože vždy vrací stejný výsledek pro libovolnou sadu hodnot argumentů pro své tři parametry.
GETDATE
není deterministický, protože je vždy vyvolán se stejným argumentem, ale hodnota, kterou vrací, se mění při každém spuštění.
Chcete-li zjistit, zda je sloupec zobrazení deterministický, použijte vlastnost IsDeterministic
funkce COLUMNPROPERTY. Chcete-li zjistit, zda je deterministický sloupec v zobrazení s vazbou schématu přesný, použijte vlastnost IsPrecise
funkce COLUMNPROPERTY
.
COLUMNPROPERTY
vrátí 1
, pokud TRUE
, 0
pokud FALSE
a NULL
pro vstup, který není platný. To znamená, že sloupec není deterministický nebo není přesný.
I když je výraz deterministický, pokud obsahuje výrazy float, přesný výsledek závisí na architektuře procesoru nebo verzi mikrokódu. Aby se zajistila integrita dat, mohou se tyto výrazy účastnit pouze jako neklíčové sloupce indexovaných zobrazení. Deterministické výrazy, které neobsahují výrazy typu float, se nazývají přesné. Přesné deterministické výrazy mohou být použity pouze v klíčových sloupcích a v klauzulích WHERE
nebo GROUP BY
indexovaných zobrazení.
Další požadavky
Kromě možností SET
a deterministických požadavků na funkci musí být splněny také následující požadavky.
Uživatel, který provádí
CREATE INDEX
, musí být vlastníkem zobrazení.Při vytváření indexu musí být možnost indexu
IGNORE_DUP_KEY
nastavená naOFF
(výchozí nastavení).Tabulky musí být odkazovány dvoučástkovými názvy,
<schema>.<tablename>
, v definici zobrazení.Uživatelem definované funkce odkazované v zobrazení musí být vytvořeny pomocí možnosti
WITH SCHEMABINDING
.Na všechny uživatelem definované funkce, na které se odkazuje v zobrazení, je nutné odkazovat pomocí dvoudílných názvů,
<schema>.<function>
.Vlastnost přístupu k datům uživatelem definované funkce musí být
NO SQL
a vlastnost externího přístupu musí býtNO
.Funkce modulu CLR (Common Language Runtime) se můžou zobrazit v seznamu výběru zobrazení, ale nemůžou být součástí definice clusterovaného indexového klíče. Funkce CLR se v
WHERE
klauzuli zobrazení ani vON
operaciJOIN
v zobrazení nezobrazují.Funkce a metody CLR uživatelem definovaných typů CLR používané v definici zobrazení musí mít vlastnosti nastavené, jak je znázorněno v následující tabulce.
Vlastnost Poznámka DETERMINISTIC = PRAVDA Musí být deklarována explicitně jako atribut metody Microsoft .NET Framework. PRECISE = PRAVDA Musí být deklarována explicitně jako atribut metody rozhraní .NET Framework. PŘÍSTUP K DATŮM = BEZ SQL Určeno nastavením atributu DataAccess
naDataAccessKind.None
aSystemDataAccess
atribut naSystemDataAccessKind.None
.EXTERNÍ PŘÍSTUP = NE Tato vlastnost má ve výchozím nastavení hodnotu NE pro rutiny CLR. Zobrazení musí být vytvořeno pomocí možnosti
WITH SCHEMABINDING
.Zobrazení musí odkazovat pouze na základní tabulky, které jsou ve stejné databázi jako zobrazení. Zobrazení nemůže odkazovat na jiná zobrazení.
Pokud existuje
GROUP BY
, musí definice VIEW obsahovatCOUNT_BIG(*)
a nesmí obsahovatHAVING
. Tato omezeníGROUP BY
platí pouze pro definici indexovaného zobrazení. Dotaz může ve svém plánu provádění použít indexované zobrazení, i když těmto omezenímGROUP BY
nevyhovují.Pokud definice zobrazení obsahuje klauzuli
GROUP BY
, klíč jedinečného clusterovaného indexu může odkazovat pouze na sloupce zadané v klauzuliGROUP BY
.Příkaz
SELECT
v definici zobrazení nesmí obsahovat následující syntaxi Transact-SQL:Transact-SQL funkce Možné alternativy COUNT
Použij COUNT_BIG
ROWSET
funkce (OPENDATASOURCE
,OPENQUERY
,OPENROWSET
aOPENXML
)Aritmetický průměr ( AVG
)Použití COUNT_BIG
aSUM
jako samostatných sloupcůStatistické agregační funkce ( STDEV
,STDEVP
,VAR
aVARP
)SUM
funkce, která odkazuje na výraz s možnou hodnotou nullPoužití ISNULL
uvnitřSUM()
k tomu, aby byl výraz nenulovýDalší agregační funkce ( MIN
,MAX
,CHECKSUM_AGG
aSTRING_AGG
)Uživatelem definované agregační funkce (SQL CLR) Klauzule SELECT element Transact-SQL Možná alternativa WITH cte AS
Běžné výrazy tabulek (CTE) WITH
SELECT
Poddotazy SELECT
SELECT [ <table>. ] *
Explicitní názvy sloupců SELECT
SELECT DISTINCT
Použijte GROUP BY
SELECT
SELECT TOP
SELECT
OVER
klauzule, která zahrnuje funkce řazení nebo agregace okenFROM
LEFT OUTER JOIN
FROM
RIGHT OUTER JOIN
FROM
FULL OUTER JOIN
FROM
OUTER APPLY
FROM
CROSS APPLY
FROM
Odvozené tabulkové výrazy (to jest použití SELECT
v klauzuliFROM
)FROM
Samo-spojení FROM
Proměnné tabulky FROM
Vložená funkce s hodnotou tabulky FROM
Funkce s hodnotami tabulky s více příkazy FROM
PIVOT
,UNPIVOT
FROM
TABLESAMPLE
FROM
FOR SYSTEM_TIME
Přímé dotazování na tabulku časové historie WHERE
Predikáty fulltextu ( CONTAINS
,FREETEXT
,CONTAINSTABLE
,FREETEXTTABLE
)GROUP BY
operátory CUBE
,ROLLUP
neboGROUPING SETS
Definovat samostatná indexovaná zobrazení pro každou kombinaci GROUP BY
sloupcůGROUP BY
HAVING
Nastavit operátory UNION
,UNION ALL
,EXCEPT
,INTERSECT
V klauzuli WHERE
použijteOR
,AND NOT
aAND
.ORDER BY
ORDER BY
ORDER BY
OFFSET
Typ zdrojového sloupce Možná alternativa Zastaralé typy sloupců s velkými hodnotami (text, ntexta image) Migrujte sloupce na varchar(max), nvarchar(max)a varbinary(max). sloupců xml nebo FILESTREAM plovoucí1 sloupců v klíči indexu Řídké sady sloupců 1 indexované zobrazení může obsahovat plovoucí sloupce; Tyto sloupce však nelze zahrnout do clusterovaného indexového klíče.
Důležitý
Indexovaná zobrazení nejsou podporována nad dočasnými dotazy (dotazy, které používají klauzuli
FOR SYSTEM_TIME
).
Doporučení pro datetime a smalldatetime
Pokud odkazujete na datetime a řetězcové literály řetězcové literály v indexovaných zobrazeních, doporučujeme explicitně převést literál na požadovaný typ data pomocí stylu deterministického formátu data. Seznam stylů formátu kalendářních dat, které jsou deterministické, naleznete v tématu CAST a CONVERT. Další informace o deterministických a nedeterministických výrazech najdete v části Důležité informace na této stránce.
Výrazy, které zahrnují implicitní převod řetězců znaků na datetime nebo smalldatetime jsou považovány za nedeterministické. Další informace naleznete v tématu Nedeterministický převod doslovných řetězců data na hodnoty DATE.
Výkonové aspekty indexovaných zobrazení
Při spuštění DML (například UPDATE
, DELETE
nebo INSERT
) na tabulce, kterou odkazuje velký počet indexovaných zobrazení nebo méně, ale složitějších indexovaných zobrazení, je potřeba aktualizovat i tato indexovaná zobrazení během provádění DML. Výsledkem je, že výkon dotazů DML může výrazně klesnout, nebo v některých případech nelze ani vytvořit plán dotazu. V takových scénářích otestujte dotazy DML před použitím v produkčním prostředí, analyzujte plán dotazu a vylaďte nebo zjednodušte příkaz DML.
Pokud chcete zabránit databázovému stroji v použití indexovaných zobrazení, použijte pokyn OPTION (EXPAND VIEWS) v dotazu. Pokud je některá z uvedených možností nesprávně nastavená, zabrání optimalizátoru v používání indexů v zobrazeních. Další informace o pokynu OPTION (EXPAND VIEWS)
naleznete v části SELECT.
Další důležité informace
Nastavení možnosti
large_value_types_out_of_row
sloupců v indexované zobrazení se dědí z nastavení odpovídajícího sloupce v základní tabulce. Tato hodnota je nastavena pomocí sp_tableoption. Výchozí nastavení sloupců vytvořených z výrazů je0
. To znamená, že velké typy hodnot jsou uloženy v řádku.Indexovaná zobrazení lze vytvořit na particionované tabulce a mohou být samy o sobě particionované.
Při zrušení zobrazení se odstraní všechny indexy v zobrazení. Všechny neclusterované indexy a automaticky vytvořené statistiky v zobrazení se při vyřazení clusterovaného indexu zahodí. Statistiky vytvořené uživatelem v zobrazení jsou zachovány. Neclusterované indexy je možné jednotlivě vynechat. Odstranění clusterovaného indexu z pohledu odebere uloženou sadu výsledků, a optimalizátor se vrátí ke zpracování pohledu jako standardního pohledu.
Indexy tabulek a zobrazení je možné zakázat. Pokud je clusterovaný index v tabulce zakázaný, indexy v zobrazeních přidružených k tabulce jsou také zakázány.
Dovolení
K vytvoření zobrazení musí uživatel uchovávat oprávnění CREATE VIEW
v databázi a ALTER
oprávnění ke schématu, ve kterém se zobrazení vytváří. Pokud se základní tabulka nachází v jiném schématu, vyžaduje se minimálně oprávnění REFERENCES
k tabulce. Pokud se uživatel, který vytváří index, liší od uživatelů, kteří zobrazení vytvořili, k samotnému vytvoření indexu je vyžadováno oprávnění ALTER
k zobrazení (zahrnuje oprávnění ALTER
na schématech).
Indexy lze vytvořit pouze v zobrazeních, která mají stejného vlastníka jako odkazovaná tabulka nebo tabulky. Tento koncept se také nazývá nedotčený řetěz vlastnictví mezi zobrazením a tabulkami. Obvykle platí, že pokud se tabulka a zobrazení nacházejí ve stejném schématu, platí stejný vlastník schématu pro všechny objekty v rámci schématu. Proto je možné vytvořit zobrazení a ne být vlastníkem zobrazení. Na druhou stranu je také možné, že jednotlivé objekty v rámci schématu mají různé explicitní vlastníky. Sloupec principal_id
v sys.tables
obsahuje hodnotu, pokud se vlastník liší od vlastníka schématu.
Vytvoření indexovaného zobrazení: příklad T-SQL
Následující příklad vytvoří zobrazení a index v tomto zobrazení v databázi 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
Další dva dotazy ukazují, jak se dá indexované zobrazení použít, i když zobrazení není zadané v klauzuli 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;
Nakonec tento příklad ukazuje dotazování přímo z indexovaného zobrazení. Automatické použití indexovaného zobrazení optimalizátorem dotazů je podporováno pouze v konkrétních edicích SQL Serveru. V edici SQL Server Standard musíte k přímému dotazování indexovaného zobrazení použít nápovědu k dotazu NOEXPAND
. Azure SQL Database a Azure SQL Managed Instance podporují automatické využívání indexovaných zobrazení bez nutnosti zadat NOEXPAND
hint. Další informace naleznete v tématu Nápovědy k tabulce (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;
Další informace naleznete v tématu CREATE VIEW.