Conseils pour diagnostiquer une requête lente «parfois»


20

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: entrez la description de l'image ici

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: entrez la description de l'image ici

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


1
Les commentaires ne sont pas pour une discussion approfondie; cette conversation a été déplacée vers le chat . Tout le monde: veuillez utiliser cette fonction pour poursuivre la discussion sur cette question.
Paul White dit GoFundMonica

étant donné que le lien ne fonctionne pas.la requête est simple, il y a une énorme différence entre le nombre réel et estimé de lignes, ce qui est un sujet de préoccupation.Je pense que le problème réside dans la requête de vue.Je pense que les données sont insuffisantes.Il devrait être proche
KumarHarsh

Avez-vous essayé d'exécuter WhoIsActive (par Adam Machanic) pendant l'exécution de la requête? whoisactive.com Il contient des informations sur les tâches en attente, qui devraient vous orienter dans la bonne direction.
MJH

Avez-vous éliminé quelque chose d'extérieur à la base de données à l'origine de cela? Peut-être une autre application provoquant des E / S synchrones sur le stockage partagé avec la base de données?
Johan

Réponses:


2

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:

OPTION(OPTIMIZE FOR(@LocationIds='xx',@StatusType='xx'))

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


1

Essayez peut-être de forcer la commande, donc vous commencez probablement toujours par la petite table (variable). Cela devient difficile avec des vues ...

    SELECT  -- lots of fields
    FROM    @LocationIds [b] WITH (NOEXPAND)
            INNER JOIN  [dbo].[ListingSearchView][a] WITH (NOEXPAND) 
                ON [a].[LocationId] = [b].[Id]
    WHERE   [a].[StatusType] = @statusType
    OPTION (FORCE ORDER);

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

    SELECT  -- lots of fields
    FROM    @LocationIds [b] WITH (NOEXPAND)
            INNER LOOP JOIN  [dbo].[ListingSearchView][a] WITH (NOEXPAND) 
                ON [a].[LocationId] = [b].[Id]
    WHERE   [a].[StatusType] = @statusType
    --leaving this here so you don't get an annoying warning 
    OPTION (FORCE ORDER);

0

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

Image du plan d'exécution estimé de l'affichage

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.

Plan d'exécution avec détails


-1

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)

CREATE NONCLUSTERED INDEX IX_ListingSearchView (LocationID, StatusType) INCLUDE (other columns...)

1
L'index que vous proposez existe déjà IX_ListingSearchView_ForAPI(voir le script dans la question).
Paul White dit GoFundMonica

1
Hé, merci pour votre réponse. Comme je l'ai dit dans ma question, je veux savoir quel est le problème avant d'appliquer un correctif. Sinon, je pourrais simplement ignorer le vrai problème. Ma question est de trouver le problème d'abord, puis la bonne solution.
RPM1984

Pouvez-vous obtenir cette requête lente dans votre environnement local? Si la même requête s'exécute parfois lentement et parfois rapidement, cela peut dépendre des paramètres d'entrée. Pouvez-vous s'il vous plaît fournir le nombre de lectures logiques et le nombre total de lignes renvoyées par votre requête lente.
Artashes Khachatryan

@ArtashesKhachatryan oui, il s'exécute parfois lentement sur local aussi. J'ai mis à jour la question avec un plan d'exécution. Je me demande si c'est lié aux requêtes lentes renvoyant plus de lignes que la rapide, comme vous l'avez dit.
RPM1984 du
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.