Dans une question précédente, est-ce une bonne idée de désactiver l'escalade de verrous lors de l'ajout de nouvelles colonnes calculées à une table? , Je crée une colonne calculée:
ALTER TABLE dbo.tblBGiftVoucherItem
ADD isUsGift AS CAST
(
ISNULL(
CASE WHEN sintMarketID = 2
AND strType = 'CARD'
AND strTier1 LIKE 'GG%'
THEN 1
ELSE 0
END
, 0)
AS BIT
) PERSISTED;
La colonne calculée est PERSISTED
, et selon la définition_colonne_calculée (Transact-SQL) :
PERSISTE
Spécifie que le moteur de base de données stockera physiquement les valeurs calculées dans la table et mettra à jour les valeurs lorsque toute autre colonne dont dépend la colonne calculée est mise à jour. Marquer une colonne calculée comme PERSISTED permet de créer un index sur une colonne calculée qui est déterministe, mais pas précis. Pour plus d'informations, consultez Index sur les colonnes calculées. Toutes les colonnes calculées utilisées comme colonnes de partitionnement d'une table partitionnée doivent être explicitement marquées PERSISTED. expression_colonne_calculée doit être déterministe lorsque PERSISTED est spécifié.
Mais lorsque j'essaie de créer un index sur ma colonne, j'obtiens l'erreur suivante:
CREATE INDEX FIX_tblBGiftVoucherItem_incl
ON dbo.tblBGiftVoucherItem (strItemNo)
INCLUDE (strTier3)
WHERE isUsGift = 1;
Impossible de créer l'index filtré 'FIX_tblBGiftVoucherItem_incl' sur la table 'dbo.tblBGiftVoucherItem' car la colonne 'isUsGift' dans l'expression de filtre est une colonne calculée. Réécrivez l'expression de filtre afin qu'elle n'inclue pas cette colonne.
Comment puis-je créer un index filtré sur une colonne calculée?
ou
Existe-t-il une solution alternative?
la source
WHERE (sintMarketID = 2 AND strType = 'CARD' AND strTier1 LIKE 'GG%')
.Réponses:
Malheureusement, depuis SQL Server 2014, il n'est pas possible de créer un
Filtered Index
emplacement où le filtre se trouve sur une colonne calculée (indépendamment du fait qu'il soit persistant ou non).Un élément Connect est ouvert depuis 2009, alors allez-y et votez pour. Peut-être que Microsoft corrigera cela un jour.
Aaron Bertrand a un article qui couvre un certain nombre d'autres problèmes avec les indices filtrés .
la source
Bien que vous ne puissiez pas créer un index filtré sur une colonne persistante, il existe une solution de contournement assez simple que vous pouvez utiliser.
À titre de test, j'ai créé une table simple avec une
IDENTITY
colonne et une colonne calculée persistante basée sur la colonne d'identité:Ensuite, j'ai créé une vue liée au schéma basée sur la table avec un filtre sur la colonne calculée:
Ensuite, j'ai créé un index cluster sur la vue liée au schéma, ce qui a pour effet de conserver les valeurs stockées dans la vue, y compris la valeur de la colonne calculée:
Insérez des données de test dans le tableau:
Créez un élément de statistiques et un index sur la vue:
L'exécution d'
SELECT
instructions sur la table avec la colonne persistante peut désormais utiliser automatiquement la vue persistante, si l'optimiseur de requête détermine qu'il est logique de le faire:Le plan d'exécution réel pour la requête ci-dessus montre que l'optimiseur de requête a choisi d'utiliser la vue persistante pour renvoyer les résultats:
Vous avez peut-être remarqué la conversion explicite dans la
WHERE
clause ci-dessus. Cette expliciteCONVERT(INT, 26)
permet à l'optimiseur de requête d'utiliser correctement l'objet de statistiques pour estimer le nombre de lignes qui seront renvoyées par la requête. Si nous écrivons la requête avecWHERE pv.TestComputedColumn = 26
, l'optimiseur de requête peut ne pas estimer correctement le nombre de lignes car 26 est en fait considéré comme unTINY INT
; cela peut empêcher SQL Server d'utiliser la vue persistante. Les conversions implicites peuvent être très douloureuses et il est avantageux d'utiliser systématiquement les types de données corrects pour les comparaisons et les jointures.Bien sûr, tous les "pièges" standard résultant de l'utilisation de la liaison de schéma s'appliquent au scénario ci-dessus; cela peut empêcher l'utilisation de cette solution de contournement dans tous les scénarios. Par exemple, il ne sera plus possible de modifier la table de base sans d'abord supprimer la liaison de schéma de la vue. Pour ce faire, vous devrez supprimer l'index cluster de la vue.
Si vous ne disposez pas de SQL Server Enterprise Edition, l'optimiseur de requête n'utilisera pas automatiquement la vue persistante pour les requêtes qui ne référencent pas directement la vue à l'aide de l'
WITH (NOEXPAND)
indicateur. Pour tirer parti de l'utilisation de la vue persistante dans les versions non Enterprise Edition, vous devrez réécrire la requête ci-dessus sur quelque chose comme:Merci à Ian Ringrose pour avoir souligné la limitation Enterprise Edition ci-dessus et à Paul White pour l'
(NOEXPAND)
astuce.Cette réponse de Paul contient des détails intéressants sur l'optimiseur de requêtes par rapport aux vues persistantes.
la source
TestComputedColumn
place. Cependant, comme l'index cluster contient toutes les données de la table / vue, j'ai décidé qu'il serait probablement préférable d'utiliser un nombre croissant monotone comme clé de clustering. Remarque, je n'ai pas réellement testé cette supposition, et elle peut en fait être incorrecte pour certaines variations de la repro.Depuis
Create Index
et sawhere
clause, cela n'est pas possible:Source: MSDN
la source
Avant de calculer les colonnes, nous utilisions des déclencheurs pour calculer la valeur des colonnes chaque fois que la ligne était modifiée ou insérée.
(Un déclencheur peut également être utilisé pour insérer / supprimer le PK de l'élément d'une deuxième table qui a ensuite été utilisée dans les requêtes.)
la source
Il s'agit d'une tentative d'améliorer le travail de Max Vernon . Dans sa solution, il propose d'utiliser 2 index sur la vue et un objet statistique.
Le 1er index est clusterisé, ce qui est en fait nécessaire car contrairement à un index non clusterisé sur une table, une erreur sera générée si la création d'un index non clusterisé sur la vue est tentée sans avoir au préalable un index clusterisé.
Le 2e index est un index non cluster, qui est utilisé comme index derrière la requête. Dans la section des commentaires de sa réponse, j'ai demandé ce qui se passerait si un index cluster était utilisé au lieu d'un index non cluster.
L'analyse suivante tente de répondre à cette question.
J'utilise son même code exact, sauf que je ne crée pas d'index non cluster sur la vue.
Je ne crée pas non plus d'objet de statistiques. Si vous suivez et utilisez SQL Server Management Studio (SSMS) pour entrer le code ci-dessous, vous devez savoir que vous pouvez voir des lignes rouges ondulées - qui ressemblent à des erreurs. Ce ne sont (probablement) pas des erreurs, mais impliquent un problème avec intellisense.
Vous pouvez désactiver Intellisense ou simplement ignorer les erreurs et exécuter les commandes. Ils doivent se terminer sans erreur.
Le plan d'exécution suivant (sans vue vue / index) est produit après l'exécution de la requête suivante sur la table:
Cela donne une référence à comparer. Notez qu'une fois la requête terminée, un objet de statistiques a été créé (_WA_Sys_00000003_1FCDBCEB). L'objet de statistiques PK_PersistedViewTest a été créé lors de la création de l'index de table en cluster.
Ensuite, la vue filtrée et l'index cluster sur cette vue sont créés:
Maintenant, essayons de relancer la requête, mais cette fois par rapport à la vue:
Le nouveau plan d'exécution est désormais:
Si l'on en croit le nouveau plan, après l'ajout de la vue et de l'index cluster sur cette vue, les statistiques semblent indiquer que le temps requis pour exécuter la requête a maintenant doublé. Notez également qu'aucun nouvel objet de statistiques n'a été créé pour prendre en charge le nouvel index après l'exécution de la requête, ce qui est différent de la requête sur la table.
Le plan de requête suggère toujours que la création d'un index non cluster serait très utile pour améliorer les performances de la requête. Cela signifie-t-il donc qu'un index non cluster doit être ajouté à la vue avant d'obtenir l'amélioration des performances souhaitée? Il y a une dernière chose à essayer. Modifiez la requête pour utiliser l'option "WITH NOEXPAND":
Il en résulte le plan de requête suivant:
Ce plan d'exécution ressemble assez à celui qui a été produit avec l'index non cluster donné dans la réponse de Max Vernon. Mais, celui-ci se fait avec un index de moins (non cluster) et un objet de statistiques en moins.
Il s'avère que l'option NOEXPAND doit être utilisée avec les versions express et standard de SQL Server pour utiliser correctement une vue indexée. Paul White a un excellent article qui expose les avantages de l'utilisation de l'option NOEXPAND. Il recommande également que cette option soit utilisée avec l'édition entreprise pour garantir que la garantie d'unicité fournie par les index de vue est utilisée par l'optimiseur.
L'analyse ci-dessus a été effectuée avec l'édition express de SQL Sever 2014. Je l'ai également essayée avec l'édition développeur de SQL Server 2016. L'option NOEXPAND ne semble pas être requise avec l'édition de développement pour obtenir des gains de performances, mais est toujours recommandée. .
Il y a moins de 5 mois, Microsoft a rendu les éditions développeur gratuites . La licence limite l'utilisation au développement uniquement, ce qui signifie que la base de données ne peut pas être utilisée dans un environnement de production. Donc, si vous avez cherché à tester des tables optimisées en mémoire, le chiffrement, R, etc., vous n'avez plus d'excuse sans licence. Je l'ai installé avec succès sur mon ordinateur il y a quelques jours avec SQL Server 2014 Express sans aucun problème.
la source