J'essaie d'améliorer les performances d'une requête qui s'exécute très lentement. Après avoir suivi le plan d'exécution réel ; J'ai trouvé qu'une recherche d'index cluster prenait 82%. Existe-t-il un moyen pour moi d'améliorer les performances sur une recherche d'index ? Ci-dessous, une image du problème Index Seek du plan d'exécution ainsi que de l'index et de la table qu'il utilise.
texte alternatif http://img340.imageshack.us/img340/1346/seek.png
Indice:
/****** Object: Index [IX_Stu] Script Date: 12/28/2009 11:11:43 ******/
CREATE CLUSTERED INDEX [IX_Stu] ON [dbo].[stu]
(
[StuKey] ASC
)WITH (PAD_INDEX = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF) ON [PRIMARY]
Tableau (certaines colonnes omises par souci de concision):
CREATE TABLE [dbo].[stu](
[StuCertKey] [int] IDENTITY(1,1) NOT NULL,
[StuKey] [int] NULL
CONSTRAINT [PK_Stu] PRIMARY KEY NONCLUSTERED
(
[StuCertKey] ASC
)WITH (PAD_INDEX = OFF, IGNORE_DUP_KEY = OFF, FILLFACTOR = 80) ON [PRIMARY]
) ON [PRIMARY]
Je généralise ici, mais ...
Une recherche d'index cluster est, dans la plupart des cas, le meilleur des cas. Les seules façons dont je peux penser pour améliorer les performances seraient:
Si cela ne renvoie que 138 lignes et que c'est si lent ... peut-être qu'il est bloqué par un autre processus? Le testez-vous de manière isolée ou d'autres utilisateurs/processus sont-ils en ligne en même temps? Ou peut-être que c'est même un problème matériel, comme une panne de disque.
Les recherches d'index clusterisé se produisent lorsque des index non clusterisés sont utilisés et ne sont pas nécessairement mauvais.
Considérez la requête suivante:
SELECT s.StuKey, s.Name, s.Address, s.City, s.State FROM stu s WHERE State='TX'
S'il n'y a qu'un index cluster sur StuKey, alors Sql Server n'a qu'une seule option, il doit analyser la table entière à la recherche de lignes où State = "TX 'et retourner ces lignes.
Si vous ajoutez un index non cluster sur State
CREATE INDEX IX_Stu_State on Stu (State)
Maintenant, le serveur SQL a une nouvelle option. Il peut choisir de rechercher en utilisant l'index non clusterisé, qui produira les lignes où State = 'TX'. Cependant, pour obtenir le retour des colonnes restantes dans SELECT, il doit rechercher ces colonnes en effectuant une recherche d'index cluster pour chaque ligne.
Si vous souhaitez réduire la recherche d'index clusterisé, vous pouvez rendre votre index "couvrant" en y incluant des colonnes supplémentaires.
CREATE INDEX IX_Stu_State2 on Stu (State) INCLUDE (name, address, city )
Cet index contient désormais toutes les colonnes nécessaires pour répondre à la requête ci-dessus. La requête effectuera une recherche d'index pour renvoyer uniquement les lignes où State = 'TX', et les colonnes supplémentaires peuvent être extraites de l'index non cluster, de sorte que l'index cluster cherche disparaît.
Une recherche d'index en cluster qui retourne 138 lignes n'est pas votre problème.
Techniquement, vous pouvez améliorer les performances de recherche en réduisant l'index clusterisé:
Les deux peuvent avoir un impact assez spectaculaire sur le temps de recherche de plage, car ils réduisent le IO et la nécessité de frapper les lectures physiques. Bien sûr, comme d'habitude, le résultat variera sur un grand nombre d'autres des facteurs, comme les colonnes que vous projetez (expulser une colonne projetée dans l'unité d'allocation BLOB peut en fait avoir des effets négatifs sur certaines requêtes). En remarque, la fragmentation n'aura généralement qu'un impact marginal sur une analyse à si courte distance. dépend.
Mais comme je l'ai dit, je doute fortement que ce soit votre vrai problème. Vous n'avez publié que des parties sélectionnées du plan et les résultats de votre propre analyse. La véritable cause profonde peut être complètement ailleurs.
Pensées...
Pourquoi IX_Stu est-il en cluster? En interne, SQL Server ajoute un "uniqueificateur" de 4 octets aux index cluster non uniques. Quelle est la justification? Cela gonfle également votre PK aussi
Quelle est la requête réelle que vous exécutez?
Enfin, pourquoi FILLFACTOR 80%?
Éditer:
Un FILLFACTOR "normal" serait de 90%, mais ce n'est qu'une règle d'or
Une requête de jointure 11? C'est très probablement votre problème. Quelles sont vos clauses JOIN, WHERE, etc.? Qu'est-ce que le plan de texte intégral?
Quelques conseils généraux: lorsque je dois faire une optimisation de requête, je commence par écrire ce que je pense que le plan d'exécution devrait être.
Une fois que j'ai décidé de ce que devrait être le plan d'exécution, j'essaie d'adapter la requête à ce plan. Les techniques pour ce faire sont différentes pour chaque SGBD et ne sont pas nécessairement transférées de l'une à l'autre, ni même, parfois, entre différentes versions du SGBD.
La chose à garder à l'esprit est que le SGBD ne peut exécuter qu'une jointure à la fois: il commence par deux tables initiales, joint celles-ci, puis prend le résultat de cette opération et le joint à la table suivante. Le but à chaque étape est de minimiser le nombre de lignes dans le jeu de résultats intermédiaire (plus correctement, de minimiser le nombre de blocs qui doivent être lus pour produire les résultats intermédiaires, mais cela signifie généralement le moins de lignes).
Que se passe-t-il si vous codez en dur vos critères OÙ , comme ceci:
SELECT StuCertKey, StuKey FROM stu
WHERE stuKey in (/* list 50 values of StuKey here */)
Si c'est encore très lent, vous avez un problème interne quelconque. Si c'est plus rapide, alors l'index n'est pas votre goulot d'étranglement, c'est le JOINs que vous faites pour créer le filtre OÙ .
Notez que SELECT *
peut être très lent s'il y a beaucoup de grandes colonnes, et surtout s'il y a des BLOBs.
Vérifiez les statistiques de l'index.
recalculer les statistiques d'index cluster résoudra le problème.
dans mon cas, je recherchais 30 enregistrements dans 40M enregistrés. le plan d'exécution indique qu'il passe par l'index clusterisé mais cela a pris environ 200 ms. et l'index n'a pas été défragmenté. après avoir recalculé ses statistiques, cela se fait en moins de 10 ms!
Avez-vous essayé une maintenance de cet index? Comme le défragmenter? Semble vraiment étrange que cela coûte autant (120,381). La recherche d'index est l'opération d'index la plus rapide, ne devrait pas prendre autant de temps. Pouvez-vous publier la requête?
Reconstruire l'index et calculer les statistiques?
La seule autre façon que je puisse penser pour l'accélérer est de partitionner la table, ce qui peut ou non être possible.