Consigli sulla diagnosi di una query lenta "a volte"


20

Ho una procedura memorizzata che restituisce risultati da una vista indicizzata tramite un indice di copertura. Di solito, funziona veloce (~ 10ms), a volte può durare fino a 8 secondi.

Ecco un esempio di esecuzione casuale (nota: questa non è lenta, ma il testo della query è lo stesso a parte il valore passato):

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

Ecco lo 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);

(nota: ho aggiunto il OPTION (RECOMPILE)suggerimento di recente dopo alcuni consigli, ma non ha aiutato.

Ecco l'indice di copertura (nota: la vista ha anche un indice cluster su ListingId, che è unico)

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

Ho messo su una traccia di profiler, con statistiche XML showplan.

Eccone uno lento (6 secondi) e il piano pertinente: inserisci qui la descrizione dell'immagine

Sembra esattamente come mi sarei aspettato ed è lo stesso piano quando la query è veloce.

Ecco lo zoom sulla parte costosa del piano, se questo aiuta: inserisci qui la descrizione dell'immagine

Ecco lo schema completo delle view / backing tables, se questo aiuta: https://pastebin.com/wh1sRcbQ

Gli appunti:

  • Gli indici sono stati deframmentati, le statistiche aggiornate.
  • Inizialmente la query era in linea con la vista, ma sono passato a SPROC per cercare di stabilizzare. Non ha aiutato
  • Aggiunta di un WITH OPTION (RECOMPILE);suggerimento (non ha funzionato, quindi non è possibile annusare i parametri?)
  • Anche altre query nel sistema a volte funzionano lentamente e non hanno problemi evidenti nel loro piano.
  • Potrebbe essere bloccato? Non sono sicuro di come confermare.

Qualche idea su cosa potrei provare dopo?

Grazie


1
I commenti non sono per una discussione estesa; questa conversazione è stata spostata in chat . Tutti: si prega di utilizzare tale funzione per ulteriori discussioni su questa domanda.
Paul White dice GoFundMonica

dato che il link non funziona. La query del processo è semplice, c'è un'enorme differenza tra il numero effettivo e stimato di righe che è un'area di preoccupazione. Penso che il problema risieda nella query vista. Penso che i dati siano insufficienti. Dovrebbe essere vicino
KumarHarsh

Hai provato a eseguire WhoIsActive (di Adam Machanic) mentre la query è in esecuzione? whoisactive.com Include informazioni sulle attività di attesa, che dovrebbero indirizzarti nella giusta direzione.
MJH

Hai eliminato qualcosa di esterno al DB che causa questo. Forse un'altra applicazione che causa l'IO sincrono allo storage condiviso con il DB?
Johan

Risposte:


2

Non credo davvero che usare il OPTION (RECOMPILE)sia un modo efficace per eliminare la possibilità di annusare i parametri.

Lo sniffing dei parametri si verifica quando SQL è confuso su una particolare query e pensa che sia nuovo perché vede nuovi parametri. È lento perché richiede più tempo per generare un nuovo piano di esecuzione.

Tutto ciò che fa è forzare SQL a produrre un nuovo piano ogni volta che è praticamente la stessa cosa. Invece, potresti voler considerare l'aggiunta di parametri predefiniti usando questo suggerimento:

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

Quando si scelgono i parametri per impostazione predefinita, assicurarsi di utilizzare un set statisticamente rappresentativo.
Ciò costringerà lo stesso piano ad essere utilizzato ogni volta ed eliminerà la possibilità di annusare i parametri. Una volta che lo fai, e determina che non ha aiutato, allora è probabilmente sicuro scartare il parametro sniffing come una possibilità.


1

Forse prova a forzare l'ordine, quindi probabilmente stai sempre iniziando con la tabella più piccola (variabile). Questo è difficile con le viste però ...

    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);

oppure puoi forzare un loop loop se in genere è così che vuoi unire la variabile della tabella alla vista, che forzerà anche l'ordine ...

    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

Scrivi il nome della procedura Store nell'Editor di query, quindi seleziona Proc store. nome e quindi selezionare Visualizza piano di esecuzione stimato o Fare clic (Ctrl + L). sotto l'immagine di questo.

Immagine del piano di esecuzione stimato di visualizzazione

quindi i piani di esecuzione vengono visualizzati proprio accanto alla scheda Messaggi nella parte inferiore dell'Editor di query. quindi nelle linee di colore verde mostra i dettagli dell'indice mancanti e fai clic con il tasto destro su quello. Quindi Nuova query si apre in una nuova scheda, quindi crea l'INDICE. quindi la tua query verrà eseguita rapidamente.

Quindi ho usato questo metodo per diagnosticare la query che lavora lentamente. e inoltre ci sono così tante query o metodi che puoi usare.

Piano di esecuzione con dettagli


-1

Se ritieni che il problema sia il blocco, ti suggerirò di utilizzare il livello di isolamento delle transazioni ottimistico Leggi istantanea impegnata (tieni presente che questo sovraccaricherà il tuo tempDB).

RIFERIMENTO: https://docs.microsoft.com/en-us/dotnet/framework/data/adonet/sql/snapshot-isolation-in-sql-server

Se il problema non è nel blocco di lettura / scrittura, puoi provare ad aggiungere indici alla tua vista (la scelta migliore degli indici dipende dalla selettività dei tuoi dati)

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

1
L'indice che suggerisci esiste già IX_ListingSearchView_ForAPI(vedi lo script nella domanda).
Paul White dice GoFundMonica

1
Ehi, grazie per la tua risposta. Come ho già detto nella mia domanda, voglio sapere qual è il problema prima di applicare una correzione. Altrimenti potrei semplicemente trascurare il vero problema. La mia domanda è prima di trovare il problema, quindi la soluzione corretta.
RPM1984,

Riesci a ottenere quella query lenta nel tuo ambiente locale? Se la stessa query a volte viene eseguita lentamente e talvolta viene eseguita rapidamente, potrebbe dipendere dai parametri di input. Potete fornire il numero di letture logiche e il numero totale di righe restituite dalla query lenta.
Artashes Khachatryan,

@ArtashesKhachatryan sì, a volte funziona lentamente anche in locale. Ho aggiornato la domanda con un piano di esecuzione. Mi chiedo se sia correlato alle query lente che restituiscono più righe rispetto a quelle veloci, come hai detto.
RPM1984,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.