Question

J'ai une vue indexée simple. Quand j'interroge, c'est assez lent. Je vous montre d'abord le schéma et les index. Ensuite, les requêtes simples. Enfin, un plan de requête screnie.

Mise à jour: preuve de solution au bas de cet article.

Schéma

Voici à quoi ça ressemble: -

CREATE view [dbo].[PostsCleanSubjectView] with SCHEMABINDING AS
    SELECT PostId, PostTypeId, 
        [dbo].[ToUriCleanText]([Subject]) AS CleanedSubject
    FROM [dbo].[Posts]

Mon udf ToUriCleanText remplace simplement divers caractères par un caractère vide. Par exemple. remplace tous les caractères '#' par ''.

Ensuite, j'ai ajouté deux index à ce sujet: -

index

Index de clé primaire (c.-à-d. index clusterisé)

CREATE UNIQUE CLUSTERED INDEX [PK_PostCleanSubjectView] ON 
    [dbo].[PostsCleanSubjectView] 
(
    [PostId] ASC
)
WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, 
      SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF,
      ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
GO

Et un index non clusterisé

CREATE NONCLUSTERED INDEX [IX_PostCleanSubjectView_PostTypeId_Subject] ON 
    [dbo].[PostsCleanSubjectView] 
(
    [CleanedSubject] ASC,
    [PostTypeId] ASC
)
WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, 
      SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF,
      ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
GO

Maintenant, cela a environ 25 000 lignes. Rien de grand du tout.

Lorsque je fais les requêtes suivantes, toutes les deux prennent environ 4 secondes impaires. WTF? Cela devrait être .. essentiellement instantané!

Requête 1

SELECT a.PostId
FROM PostsCleanSubjectView a 
WHERE a.CleanedSubject = 'Just-out-of-town'

Requête 2 (ajout d'un autre élément de clause where)

SELECT a.PostId
FROM PostsCleanSubjectView a 
WHERE a.CleanedSubject = 'Just-out-of-town' AND a.PostTypeId = 1

Qu'est-ce que j'ai mal fait? Les UDF font-ils des bêtises? J'ai pensé que, parce que j'avais indexé cette vue, elle serait matérialisée. En tant que tel, il n’aurait pas à calculer cette colonne de chaîne.

Voici un aperçu du plan de requête, si cela peut vous aider: - alt text

Notez également l'index qu'il utilise? Pourquoi utilise-t-il cet index?

Cet index est ...

CREATE NONCLUSTERED INDEX [IX_Posts_PostTypeId_Subject] ON [dbo].[Posts] 
(
    [PostTypeId] ASC,
    [Subject] ASC
)
WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, 
      SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, 
      ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
GO

Alors oui, des idées des gens?

Mise à jour 1: ajout du schéma pour le fichier udf.

CREATE FUNCTION [dbo].[ToUriCleanText]
(
    @Subject NVARCHAR(300)
)
RETURNS NVARCHAR(350) WITH SCHEMABINDING
AS 
BEGIN
   <snip>
   // Nothing insteresting in here. 
   //Just lots of SET @foo = REPLACE(@foo, '

Mise à jour 2: solution

Oui, c'est parce que je n'utilisais pas l'index sur la vue et que je devais m'assurer manuellement que je ne développais pas la vue. Le serveur est Sql Server 2008 Standard Edition. La réponse complète est ci-dessous. Voici la preuve, WITH (NOEXPAND) texte alternatif

Merci à tous de m'avoir aidé à résoudre ce problème:)

, ''), etc. END

Mise à jour 2: solution

Oui, c'est parce que je n'utilisais pas l'index sur la vue et que je devais m'assurer manuellement que je ne développais pas la vue. Le serveur est Sql Server 2008 Standard Edition. La réponse complète est ci-dessous. Voici la preuve, WITH (NOEXPAND) texte alternatif

Merci à tous de m'avoir aidé à résoudre ce problème:)

Était-ce utile?

La solution

Quelle édition de SQL Server? Je pense que seules Enterprise et Developer Edition utiliseront les vues indexées automatiquement, les autres la prenant en charge à l'aide d'indices de requête.

SELECT a.PostId
FROM PostsCleanSubjectView a WITH (NOEXPAND)
WHERE a.CleanedSubject = 'Just-out-of-town' AND a.PostTypeId = 1

De Indicateurs de requête (Transact SQL) sur MSDN :

  

La vue indexée n'est pas développée uniquement si elle est référencée directement dans la partie SELECT de la requête et que WITH (NOEXPAND) ou WITH (NOEXPAND, INDEX (valeur_index [, ... n])) est spécifiée.

Autres conseils

Je vois un signe @ dans le code de requête de votre plan d'exécution. Une variable chaîne est impliquée.

Sql Server a un comportement NASTY si le type de la variable chaîne ne correspond pas au type de la colonne chaîne dans l'index. Sql Server va ... convertir la colonne entière en ce type, effectuer une recherche rapide, puis jeter l'index converti afin qu'il puisse refaire la totalité de la requête suivante.

Simon l'a compris - mais voici des détails plus utiles: http: // msdn.microsoft.com/en-us/library/ms187373.aspx

  

Si une requête contient des références à des colonnes présentes à la fois dans une vue indexée et dans des tables de base et que l'optimiseur de requête détermine que l'utilisation de la vue indexée constitue la meilleure méthode pour exécuter la requête, il optimise l'index de la vue. . Cette fonction est appelée correspondance de vue indexée . Elle est prise en charge uniquement dans les éditions SQL Server Enterprise et Developer.

     

Toutefois, pour que l'optimiseur considère les vues indexées à mettre en correspondance ou utilise une vue indexée référencée avec l'indicateur NOEXPAND, les options SET suivantes doivent être définies sur ON:

Donc, ce qui se passe ici est que la correspondance de vue indexée ne fonctionne pas. Assurez-vous que vous utilisez les éditions Enterprise ou Developer de Sql Server (très probablement). Puis vérifiez vos options SET en fonction de l'article.

J'ai récemment construit une grande base de données contenant des centaines de millions d'enregistrements des détails des appels. Certaines fonctions que j'utilisais dans les requêtes et les vues sont devenues des colonnes calculées persistantes. Cela fonctionnait beaucoup mieux car je pouvais indexer sur la colonne calculée.

Comme je n'utilisais pas SQL Enterprise, je n'ai donc pas eu la possibilité d'utiliser des vues indexées. La vue indexée est-elle supposée être capable d’indexer les résultats déterministes de la FDU?

Je suppose qu'il doit appeler cette fonction pour chaque ligne avant de pouvoir effectuer la comparaison dans votre clause where. J'exposerais le sujet, lancerais directement la vérification de la requête et verrais comment les temps fonctionnaient. J'ai généralement constaté beaucoup de lenteur chaque fois que je modifie une valeur à l'aide d'une fonction, puis que je l'utilise dans la clause where ...

Quel avantage recherchez-vous en utilisant une vue indexée? N'est-il pas possible d'indexer correctement les tables elles-mêmes? Sans justification valable, vous ajoutez de la complexité et demandez à l’optimiseur de traiter davantage d’objets de base de données avec moins de souplesse.

Avez-vous évalué la même logique de requête avec des index standard?

Le mélange dans la logique UDF brouille encore plus les choses.

Si vous souhaitez simplement conserver la valeur de retour d'un fichier UDF, considérez une colonne calculée persistante plutôt qu'une vue indexée.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top