Créer des vues indexées

S’applique à :SQL ServerAzure SQL DatabaseAzure SQL Managed Instance

Cet article décrit comment créer des index sur une vue. Le premier index créé sur une vue doit être un index cluster unique. Après avoir créé l'index cluster unique, vous pouvez créer davantage d'index non cluster. La création d’un index cluster unique sur une vue améliore les performances des requêtes, car la vue est stockée dans la base de données de la même façon qu’une table avec un index cluster est stockée. L'optimiseur de requête peut utiliser des vues indexées pour accélérer l'exécution des requêtes. La vue n’a pas besoin d’être référencée dans la requête de l’optimiseur pour prendre en compte cette vue pour une substitution.

Étapes

Les étapes suivantes de création d'une vue indexée sont essentielles à la réussite de l'implémentation de la vue indexée :

  1. Vérifiez que les SET options sont correctes pour toutes les tables existantes qui seront référencées dans la vue.
  2. Vérifiez que les options SET de la session sont définies correctement avant de créer des tables et la vue.
  3. Vérifiez que la définition de la vue est déterministe.
  4. Vérifiez que la table de base a le même propriétaire que la vue.
  5. Créez la vue en utilisant l’option WITH SCHEMABINDING.
  6. Créez l'index cluster unique sur la vue.

Important

Lors de l’exécution UPDATE, DELETE ou INSERT des opérations (langage de manipulation de données ou DML) sur une table référencée par un grand nombre de vues indexées, ou moins, mais moins, mais des vues indexées très complexes, ces vues indexées référencées doivent également être mises à jour. Par conséquent, les performances des requêtes DML peuvent se dégrader considérablement ou, dans certains cas, un plan de requête ne peut même pas être produit. Dans de tels scénarios, testez vos requêtes DML avant une utilisation en production, analysez le plan de requête et optimisez/simplifiez l’instruction DML.

Options SET requises pour les vues indexées

L’évaluation de la même expression peut produire des résultats différents dans le moteur de base de données quand différentes options SET sont actives lorsque la requête est exécutée. Par exemple, si l’option SET CONCAT_NULL_YIELDS_NULL est définie sur ON, l’expression 'abc' + NULL retourne la valeur NULL. Cependant, si l’option CONCAT_NULL_YIELDS_NULL est définie sur OFF, la même expression produit 'abc'.

Pour pouvoir gérer correctement les vues et retourner des résultats cohérents, les vues indexées nécessitent des valeurs fixes pour plusieurs options SET. Les options SET du tableau suivant doivent être définies sur les valeurs indiquées dans la colonne Valeur obligatoire chaque fois que les conditions suivantes se produisent :

  • La vue et les index suivants sur la vue sont créés.
  • Tables de base référencées dans la vue quand celle-ci est créée.
  • Une insertion, une mise à jour ou une suppression est exécutée sur une table qui participe à la vue indexée. Cette exigence inclut des opérations telles que la copie en bloc, la réplication et les requêtes distribuées.
  • L'optimiseur de requête utilise la vue indexée pour générer le plan de requête.
Options définies Valeur requise Valeur de serveur par défaut Default

Valeur OLE DB et ODBC
Default

Valeur DB-Library
ANSI_NULLS ACTIVÉ ACTIVÉ ACTIVÉ OFF
ANSI_PADDING ACTIVÉ ACTIVÉ ACTIVÉ OFF
ANSI_WARNINGS 1 ACTIVÉ ACTIVÉ ACTIVÉ OFF
ARITHABORT ACTIVÉ ACTIVÉ OFF OFF
CONCAT_NULL_YIELDS_NULL ACTIVÉ ACTIVÉ ACTIVÉ OFF
NUMERIC_ROUNDABORT OFF OFF OFF OFF
QUOTED_IDENTIFIER ACTIVÉ ACTIVÉ ACTIVÉ OFF

1 Définir ANSI_WARNINGS sur ON définit implicitement ARITHABORT sur ON.

Si vous utilisez une connexion serveur OLE DB ou ODBC, la seule valeur qui doit être modifiée est le paramètre ARITHABORT. Toutes les valeurs de la bibliothèque de bases de données doivent être définies correctement au niveau du serveur à l’aide sp_configure de l’application ou à partir de l’application à l’aide de la SET commande.

Important

Nous vous recommandons vivement de définir l’option ARITHABORT utilisateur à ON l’échelle du serveur dès que la première vue indexée ou l’index sur une colonne calculée est créée dans n’importe quelle base de données sur le serveur.

Exigence de vue déterministe

La définition d’une vue indexée doit être déterministe. Une vue est déterministe si toutes les expressions de la liste de sélection, ainsi que les clauses WHERE et GROUP BY sont déterministes. Les expressions déterministes retournent toujours le même résultat chaque fois qu’elles sont évaluées avec un ensemble spécifique de valeurs d’entrée. Seules les fonctions déterministes peuvent participer à des expressions déterministes. Par exemple, la fonction DATEADD est déterministe, car elle retourne toujours le même résultat pour un groupe donné de valeurs d’arguments pour ses trois paramètres. GETDATE n’est pas déterministe, car elle est toujours appelée avec le même argument, mais la valeur qu’elle retourne change chaque fois qu’elle est exécutée.

Pour déterminer si une colonne d’affichage est déterministe, utilisez la IsDeterministic propriété de la fonction COLUMNPROPERTY . Pour déterminer si une colonne déterministe dans une vue avec une liaison de schéma est précise, utilisez la IsPrecise propriété de la COLUMNPROPERTY fonction. COLUMNPROPERTYretourne 1 si , 0 si FALSETRUE, et NULL pour l’entrée qui n’est pas valide. Cela signifie que la colonne n’est pas déterministe ou pas précise.

Même si une expression est déterministe, si elle contient des expressions flottantes, le résultat exact dépend de l'architecture du processeur ou de la version du microcode. Pour garantir l'intégrité des données, ces expressions peuvent participer seulement sous forme de colonnes non clés de vues indexées. Les expressions déterministes qui ne contiennent pas d’expressions float sont appelées précises. Seules les expressions déterministes précises peuvent participer à des colonnes clés et dans les clauses WHERE et GROUP BY des vues indexées.

Autres conditions requises

Les exigences suivantes doivent également être remplies, en plus des SET options et des exigences de fonction déterministes

  • L’utilisateur qui exécute CREATE INDEX doit être le propriétaire de la vue.

  • Lorsque vous créez l’index, l’option IGNORE_DUP_KEY d’index doit être définie OFF sur (paramètre par défaut).

  • Les tables doivent être référencées par des noms en deux parties, schéma.nom_table, dans la définition de la vue.

  • Les fonctions définies par l’utilisateur référencées dans la vue doivent avoir été créées avec l’option WITH SCHEMABINDING.

  • Toutes les fonctions définies par l’utilisateur référencées dans la vue doivent être référencées par des noms en deux parties, <schéma>.<fonction>.

  • La propriété d’accès aux données d’une fonction définie par l’utilisateur doit avoir la valeur NO SQL, et la propriété d’accès externe doit avoir la valeur NO.

  • Les fonctions CLR (Common Language Runtime) peuvent apparaître dans la liste de sélection de la vue, mais ne peuvent pas faire partie de la définition de la clé d’index cluster. Les fonctions CLR ne peuvent pas apparaître dans la clause WHERE de la vue ou dans la clause ON d’une opération JOIN dans la vue.

  • Les propriétés des méthodes et fonctions CLR des types CLR définis par l'utilisateur employés dans la définition de vue doivent être définies de la manière illustrée dans le tableau suivant.

    Property Note
    DETERMINISTIC = TRUE Doit être déclarée explicitement comme attribut de la méthode Microsoft .NET Framework.
    PRECISE = TRUE Doit être déclarée explicitement comme attribut de la méthode .NET Framework.
    DATA ACCESS = NO SQL Déterminé par la définition de l’attribut sur DataAccessKind.None et SystemDataAccess de l’attribut DataAccess sur SystemDataAccessKind.None.
    EXTERNAL ACCESS = NO Cette propriété a la valeur NO par défaut pour les routines CLR.
  • La vue doit être créée avec l’option WITH SCHEMABINDING.

  • La vue doit référencer seulement des tables de base qui sont dans la même base de données que la vue. La vue ne peut pas référencer d’autres vues.

  • Si la clause GROUP BY est présente, la définition VIEW doit contenir COUNT_BIG(*), mais pas HAVING. Ces restrictions de GROUP BY sont applicables seulement à la définition de la vue indexée. Une requête peut utiliser une vue indexée dans son plan d’exécution même si elle ne répond pas à ces GROUP BY restrictions.

  • Si la définition de la vue contient une clause GROUP BY, la clé de l’index cluster unique peut référencer seulement les colonnes définies dans la clause GROUP BY.

  • L’instruction SELECT dans la définition de vue ne doit pas contenir la syntaxe Transact-SQL suivante :

    Fonction Transact-SQL Alternatives possibles
    COUNT Utiliser COUNT_BIG
    Fonctions ROWSET (OPENDATASOURCE, , OPENROWSETOPENQUERYet OPENXML)
    Arithmétique AVG Utiliser COUNT_BIG et SUM comme colonnes distinctes
    Fonctions d’agrégation statistique (STDEV, , STDEVPVARet VARP)
    Fonction SUM qui référence une expression acceptant les valeurs Null Utiliser ISNULL à l’intérieur SUM() pour rendre l’expression non nullable
    Autres fonctions d’agrégation (MIN, , MAXCHECKSUM_AGGet STRING_AGG)
    Fonctions d’agrégation définies par l’utilisateur (SQL CLR)
    Clause SELECT Élément Transact-SQL Alternative possible
    WITH cte AS Expressions de table courantes (CTE) WITH
    SELECT Sous-requêtes
    SELECT SELECT [ <table>. ] * Nommer explicitement des colonnes
    SELECT SELECT DISTINCT Utiliser GROUP BY
    SELECT SELECT TOP
    SELECT Clause OVER, qui inclut des fonctions de classement ou d’agrégation de fenêtre
    FROM LEFT OUTER JOIN
    FROM RIGHT OUTER JOIN
    FROM FULL OUTER JOIN
    FROM OUTER APPLY
    FROM CROSS APPLY
    FROM Expressions de table dérivées (c’est-à-dire, utilisation SELECT dans la FROM clause)
    FROM Jointures réflexives
    FROM Variables de table
    FROM Fonction table inline
    FROM Fonction table à plusieurs instructions
    FROM PIVOT, UNPIVOT
    FROM TABLESAMPLE
    FROM FOR SYSTEM_TIME Interroger directement la table d’historique temporel
    WHERE Prédicats de texte intégral (CONTAINS, , FREETEXTCONTAINSTABLE, FREETEXTTABLE)
    GROUP BY Opérateurs CUBE, ROLLUP ou GROUPING SETS Définir des vues indexées distinctes pour chaque combinaison de GROUP BY colonnes
    GROUP BY HAVING
    Opérateurs de jeu UNION, UNION ALL, EXCEPT, INTERSECT Utiliser OR, AND NOTet AND dans la WHERE clause respectivement
    ORDER BY ORDER BY
    ORDER BY OFFSET
    Type de colonne source Alternative possible
    Texte de colonne de grande valeur déconseillé, texte ntext et image Migrez les colonnes vers varchar(max), nvarchar(max)et varbinary(max) respectivement.
    colonnes xml ou FILESTREAM
    float1 colonnes dans la clé d’index
    Jeux de colonnes éparses

    1 La vue indexée peut contenir des colonnes flottantes . Toutefois, ces colonnes ne peuvent pas être incluses dans la clé d’index cluster.

    Important

    Les vues indexées ne sont pas prises en charge en plus des requêtes temporelles (qui utilisent la clause FOR SYSTEM_TIME).

recommandations datetime et smalldatetime

Si vous faites référence aux littéraux de chaîne datetime et smalldatetime au sein de vues indexées, il est recommandé de convertir explicitement le littéral en type date souhaité à l’aide d’un style de format de date déterministe. Pour obtenir la liste des styles de format de date déterministes, consultez CAST et CONVERT (Transact-SQL). Pour plus d’informations sur les expressions déterministes et non déterministes, consultez la section Considérations de cette page.

Les expressions qui impliquent une conversion implicite de chaînes de caractères en datetime ou smalldatetime sont considérées comme non déterministes. Pour plus d’informations, consultez Conversion non déterministe de chaînes de date littérale en valeurs DATE.

Considérations sur les performances avec les vues indexées

Lorsque vous exécutez DML (par UPDATEexemple, DELETE ou INSERT) sur une table référencée par un grand nombre de vues indexées, ou moins, mais moins de vues indexées, ces vues indexées doivent également être mises à jour pendant l’exécution de DML. Par conséquent, les performances des requêtes DML peuvent dégrader considérablement, ou dans certains cas, un plan de requête ne peut même pas être généré. Dans de tels scénarios, testez vos requêtes DML avant une utilisation en production, analysez le plan de requête et optimisez/simplifiez l’instruction DML.

Pour empêcher le moteur de base de données d’utiliser des vues indexées, incluez l’indicateur OPTION (EXPAND VIEWS) sur la requête. En outre, si des options sont définies incorrectement, l'optimiseur ne peut pas utiliser les index des vues. Pour plus d’informations sur l’indicateurOPTION (EXPAND VIEWS), consultez SELECT (Transact-SQL).

Considérations supplémentaires

  • La valeur de l’option large_value_types_out_of_row des colonnes contenues dans une vue indexée est héritée de la valeur de la colonne correspondante dans la table de base. Cette valeur est définie à l’aide de sp_tableoption. La valeur par défaut des colonnes constituées à partir d'expressions est 0. Cela signifie que les types de valeurs élevées sont stockés dans la ligne.

  • Des vues indexées peuvent être créées sur une table partitionnée, et elles peuvent elles-mêmes être partitionnées.

  • Si une vue est supprimée, tous ses index le sont également. Tous les index non cluster et les caractéristiques créées automatiquement d'une vue sont supprimés lorsque son index cluster l'est. Les statistiques créées par l'utilisateur sur la vue sont conservées. Les index non cluster peuvent toutefois être supprimés individuellement. Lorsque l'index cluster de la vue est supprimé, le jeu de résultats stocké est aussi supprimé, et l'optimiseur traite de nouveau la vue comme une vue standard.

  • Les index sur les tables et les vues peuvent être désactivés. Lorsqu'un index cluster sur une table est désactivé, les index sur les vues associées à la table le sont également.

Autorisations

Pour créer la vue, un utilisateur a besoin de l’autorisation CREATE VIEW dans la base de données et de l’autorisation ALTER sur le schéma où la vue est créée. Si la table de base se trouve dans un autre schéma, REFERENCES est l’autorisation minimale nécessaire sur la table. Si l’utilisateur qui crée l’index diffère des utilisateurs qui ont créé la vue, pour la création d’index seule, l’autorisation ALTER sur la vue est requise (couverte par ALTER sur le schéma).

Les index peuvent uniquement être créés sur les vues qui ont le même propriétaire que la table ou les tables référencées. Il s’agit également d’une chaîne de propriété intacte entre la vue et la ou les tables. En règle générale, lorsque la table et la vue résident dans le même schéma, le même propriétaire de schéma s’applique à tous les objets du schéma. Par conséquent, il est possible de créer une vue et de ne pas être le propriétaire de la vue. En revanche, il est également possible que les objets individuels d’un schéma aient des propriétaires explicites différents. La principal_id colonne dans sys.tables contient une valeur si le propriétaire est différent du propriétaire du schéma.

Créer une vue indexée : un exemple T-SQL

L’exemple suivant crée une vue et un index sur cette vue, dans la AdventureWorks base de données.

--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

Les deux requêtes suivantes montrent comment l’affichage indexé peut être utilisé, même si la vue n’est pas spécifiée dans la FROM clause.

--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
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
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;

Enfin, cet exemple montre l’interrogation directement à partir de la vue indexée. Avant SQL Server 2016 (13.x) Service Pack 1, l’utilisation automatique d’une vue indexée par l’optimiseur de requête est prise en charge seulement dans certaines éditions de SQL Server. Dans l’édition SQL Server Standard, vous devez utiliser l’indicateur NOEXPAND de requête pour interroger directement la vue indexée. Depuis SQL Server 2016 (13.x) Service Pack 1, toutes les éditions prennent en charge l’utilisation automatique d’une vue indexée. Azure SQL Database et Azure SQL Managed Instance prennent également en charge l’utilisation automatique de vues indexées sans spécification de l’indicateur NOEXPAND. Pour plus d’informations, consultez Indicateurs de table (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;

Pour plus d’informations, consultez CREATE VIEW (Transact-SQL).

Étapes suivantes