2016-01-07 7 views
6

Perdonami se questo è un duplicato. Il più vicino che ho trovato è stato Random timeout running a stored proc - drop recreate fixes ma non sono sicuro che le risposte relative alla ricompilazione della stored procedure siano valide.La stored procedure SQL di Azure danneggiata potrebbe essere risolta solo con la funzione di creazione di punti di ripristino

Ho un database SQL di Azure, l'ultima versione, che ha molto traffico da un front-end dell'app Web di Azure. Ho un lavoro remoto notturno che esegue un batch per ricostruire gli indici nel database SQL di Azure in quanto sembra essere di grande aiuto per il controllo delle dimensioni e delle prestazioni del database.

Normalmente, la ricostruzione degli indici richiede circa 20 minuti. La scorsa notte è scaduto dopo 2 ore. Il gestore degli errori in quel batch non ha registrato errori.

Subito dopo l'avvio degli indici di ricostruzione, una particolare procedura memorizzata inizia a scadere per ogni client che la chiama. Altre stored procedure che utilizzavano le stesse tabelle non presentavano alcun problema. Quando ho scoperto il problema, ho potuto alleviare tutti i timeout e i processi sospesi modificando la stored procedure per tornare immediatamente. Quando ho modificato di nuovo la stored procedure per comportarmi normalmente, i problemi sono riapparsi immediatamente. La mia comprensione è che l'alterazione della stored procedure lo ha costretto a ricompilare, ma ciò non ha risolto il problema.

In definitiva, ho completamente abbandonato e ricreato la procedura con il codice originale e il problema è stato risolto.

Questa procedura e lo schema utilizzato sono stati completamente stabili per molti mesi. La stessa procedura è abbastanza semplice:

CREATE Procedure [dbo].[uspActivityGet] (@databaseid uniqueidentifier) AS 
begin 
    SET NOCOUNT ON; 
    --There may be writing activities to the table asynchronously, do not use nolock on tblActivity - the ActivityBlob might be null in a dirty read. 
    select top 100 a.Id, h.HandsetNumber, a.ActivityBlob, a.ActivityReceived 
    from dbo.tblDatabases d with(nolock) join dbo.tblHandsets h with(nolock) on d.DatabaseId = h.DatabaseId join dbo.tblActivity a on h.Id = a.HandsetId 
    where d.DatabaseId = @databaseid and a.ActivitySent is null 
    order by a.ActivityReceived 
end 

Mentre la procedura si bloccano e il tempo fuori con qualcosa di simile:

exec dbo.uspActivityGet 'AF3EA01B-DB22-4A39-9E1C-D096D2DF1215' 

L'esecuzione del select identico in una finestra di query sarebbe tornato prontamente e con successo:

declare @databaseid uniqueidentifier; set @databaseid = 'AF3EA01B-DB22-4A39-9E1C-D096D2DF1215' 
select top 100 a.Id, h.HandsetNumber, a.ActivityBlob, a.ActivityReceived 
from dbo.tblDatabases d with(nolock) join dbo.tblHandsets h with(nolock) on d.DatabaseId = h.DatabaseId join dbo.tblActivity a on h.Id = a.HandsetId 
where d.DatabaseId = @databaseid and a.ActivitySent is null 
order by a.ActivityReceived 

Qualche idea su come impedire che ciò accada in futuro? Grazie.

Modifica - Aggiunta esecuzione piano Schermate Execution Plan of stored procedure above

Modifica - Aggiunta query utilizzata per visualizzare i processi in esecuzione. Ce n'erano molti, indovinando approssimativamente 150, nello stato sospeso e erano tutti per la stessa procedura memorizzata: uspActivityGet. Inoltre, la percentuale di I/O dati è stata esaurita per tutto il tempo in cui normalmente viene eseguita tra il 20 e il 40% nei momenti di picco della domanda. Non ricordo quale fosse il tipo di attesa. Ecco la query utilizzata per vederlo.

select * from sys.dm_Exec_requests r with(nolock) CROSS APPLY sys.dm_exec_sql_text(r.sql_handle) order by r.total_elapsed_time desc 

Modifica - È successo di nuovo stasera. Ecco il piano di esecuzione della stessa procedura durante il problema. Dopo aver rilasciato e creato nuovamente la procedura, il piano di esecuzione è tornato alla normalità e il problema è stato risolto.

Durante il problema, sp_executesql con la query identica impiegava circa 5 minuti per essere eseguito e credo che sia rappresentativo di ciò che stava accadendo. C'erano circa 50 istanze di uspActivityGet sospese con tipo di attesa SLEEP_TASK o IO_QUEUE_LIMIT.

Forse la prossima domanda è perché la ricostruzione dell'indice o altra manutenzione notturna lo fa al piano di esecuzione?

enter image description here

+0

altre procedure che non presentano problemi utilizzano gli stessi join? forse diverse procedure sfruttano diversi indici? fa 'd.DatabaseId' è indicizzato? sono richiesti i suggerimenti 'NOLOCK'? forse i problemi di indicizzazione sono nascosti da quel suggerimento? cosa succede se si esegue la query da SSMS quando la procedura non riesce? – Paolo

+0

@Paolo che esegue l'istruzione select identica in una finestra di query restituirebbe prontamente e con successo. – RJBreneman

+0

Sei in grado di dire se il proc è bloccato o fare qualcosa per un tempo molto lungo o qualcos'altro? Quando si fornisce il GUID come costante nella query, viene modificato il modo in cui SQL Server costa la query, pertanto il test non esegue realmente entrambe le query nello stesso modo. Prova a testare con sp_executesql N '- la tua query', N '@ databaseid uniqueidentifier', '- your param' e vedere se funziona ancora velocemente o si impantana. Inoltre, condividi i tuoi piani di esecuzione in modo da poter vedere che cosa stava pensando SQL Server – SQLmojoe

risposta

1

Gli indizi sono nella query e il piano di esecuzione fastidioso. Vedi Poor Performance with Parallelism and Top

Il normale piano di esecuzione sembra abbastanza efficiente e non dovrebbe essere ricompilato a condizione che lo schema pertinente non cambi. Voglio anche evitare il parallelismo in questa query. Ho aggiunto le seguenti due opzioni alla richiesta di garanzia su entrambi i punti e tutto è di nuovo felice.

OPTION (KEEPFIXED PLAN, MAXDOP 1) 
+0

Bello vedere che hai risolto =) –