J'ai une procédure stockée qui renvoie les résultats d'une vue indexée via un index de couverture. Habituellement, il fonctionne rapidement (~ 10 ms), parfois il peut durer jusqu'à 8 secondes.
Voici un exemple d'exécution aléatoire (remarque: ce n'est pas lent, mais le texte de la requête est le même en dehors de la valeur transmise):
declare @p2 dbo.IdentityType
insert into @p2 values(5710955)
insert into @p2 values(5710896)
insert into @p2 values(5710678)
insert into @p2 values(5710871)
insert into @p2 values(5711103)
insert into @p2 values(6215197)
insert into @p2 values(5710780)
exec ListingSearch_ByLocationAndStatus @statusType=1,@locationIds=@p2
Voici le SPROC:
ALTER PROCEDURE [dbo].[ListingSearch_ByLocationAndStatus]
@LocationIds IdentityType READONLY,
@StatusType TINYINT
AS
BEGIN
SET NOCOUNT ON;
SELECT -- lots of fields
FROM [dbo].[ListingSearchView][a] WITH (NOEXPAND)
INNER JOIN @LocationIds [b] ON [a].[LocationId] = [b].[Id]
WHERE [a].[StatusType] = @statusType
OPTION (RECOMPILE);
(Remarque: j'ai ajouté l' OPTION (RECOMPILE)
indice récemment après quelques conseils, mais cela n'a pas aidé.
Voici l'index de couverture (remarque: la vue possède également un index clusterisé ListingId
, qui est unique)
CREATE NONCLUSTERED INDEX [IX_ListingSearchView_ForAPI] ON [dbo].[ListingSearchView]
(
[LocationId] ASC,
[StatusType] ASC
)
INCLUDE ( -- all the fields in the query) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
GO
J'ai mis une trace de profileur, avec des statistiques XML showplan.
En voici un lent (6 secondes), et le plan pertinent:
Ressemble exactement à ce que j'attendais, et c'est le même plan lorsque la requête est rapide.
Voici le zoom sur la partie coûteuse du plan, si cela vous aide:
Voici le schéma complet des tables de visualisation / sauvegarde, si cela vous aide: https://pastebin.com/wh1sRcbQ
Remarques:
- Les index ont été défragmentés, les statistiques à jour.
- À l'origine, la requête était en ligne avec la vue, mais je suis passé à SPROC pour essayer de stabiliser. Ça n'a pas aidé.
- Ajout d'un
WITH OPTION (RECOMPILE);
indice (n'a pas fonctionné, ne peut donc pas être un reniflement de paramètre?) - D'autres requêtes dans le système s'exécutent également parfois lentement, et elles n'ont également aucun problème évident dans leur plan.
- Peut-être verrouillé? Je ne sais pas comment confirmer.
Des idées sur ce que je pourrais essayer ensuite?
Merci
Réponses:
Je ne pense vraiment pas que l'utilisation de la
OPTION (RECOMPILE)
soit un moyen efficace d'éliminer la possibilité de renifler les paramètres.Le reniflage de paramètres se produit lorsque SQL est confus au sujet d'une requête particulière et pense que son nouveau parce qu'il voit de nouveaux paramètres. C'est lent car cela prend plus de temps pour générer un nouveau plan d'exécution.
Tout ce que cette option fait est de forcer SQL à produire un nouveau plan à chaque fois, ce qui est à peu près la même chose. Au lieu de cela, vous voudrez peut-être envisager d'ajouter des paramètres par défaut à l'aide de cet indice:
Lorsque vous choisissez des paramètres par défaut, assurez-vous d'utiliser un ensemble statistiquement représentatif.
Cela forcera le même plan à être utilisé à chaque fois et éliminera la possibilité de renifler les paramètres. Une fois que vous avez fait cela et déterminé que cela n'a pas aidé, il est probablement sûr de rejeter le reniflage de paramètres comme une possibilité.
la source
Essayez peut-être de forcer la commande, donc vous commencez probablement toujours par la petite table (variable). Cela devient difficile avec des vues ...
ou vous pouvez forcer une jointure en boucle si c'est généralement la façon dont vous souhaitez joindre la variable de table à la vue, ce qui forcera également l'ordre ...
la source
Écrivez le nom de la procédure Store dans l'éditeur de requête, puis sélectionnez le processus Store. nom, puis sélectionnez le plan Afficher l'exécution estimée ou cliquez sur (Ctrl + L). ci-dessous l'image de cela.
puis Plans d'exécution s'affiche juste à côté de l'onglet Messages en bas de l'éditeur de requête. puis dans les lignes de couleur verte, affichez les détails manquants de l'index et faites un clic droit dessus. Ensuite, Nouvelle requête s'ouvre dans un nouvel onglet puis créez l'INDEX. alors votre requête s'exécute rapidement.
J'ai donc utilisé cette méthode pour diagnostiquer la requête qui travaille lentement. et il y a aussi tellement de requêtes ou de méthodes que vous pouvez utiliser.
la source
Si vous pensez que le problème est lié au blocage, je vous suggérerai d'utiliser un niveau d'isolation des transactions optimisé Lire l'instantané validé (gardez à l'esprit que cela entraînera des frais généraux sur votre tempDB).
RÉFÉRENCE: https://docs.microsoft.com/en-us/dotnet/framework/data/adonet/sql/snapshot-isolation-in-sql-server
Si le problème n'est pas dans le blocage en lecture / écriture, vous pouvez essayer d'ajouter des index sur votre vue (le meilleur choix d'index dépend de la sélectivité de vos données)
la source
IX_ListingSearchView_ForAPI
(voir le script dans la question).