2016-01-07 9 views
6

Przepraszam, jeśli jest to duplikat. Najbliższe, jakie mogłem znaleźć, to Random timeout running a stored proc - drop recreate fixes, ale nie jestem pewien, czy odpowiedzi na to pytanie dotyczą rekompilacji procedury przechowywanej.Uszkodzona procedura składowana SQL Azure SQL może zostać naprawiona tylko przez odtworzenie ponownie:

Mam bazę danych Azure SQL, najnowszą wersję, która ma duży ruch z interfejsu aplikacji internetowej Azure. Mam nocne zlecenie zdalne, które uruchamia partię, aby odbudować indeksy w bazie danych Azure SQL, ponieważ wydaje się, że bardzo pomaga to w kontrolowaniu wielkości i wydajności bazy danych.

Zazwyczaj odbudowywanie indeksów trwa około 20 minut. Ostatniej nocy upłynął limit czasu po 2 godzinach. Procedura obsługi błędów w tej grupie nie zarejestrowała żadnych błędów.

Wkrótce po rozpoczęciu przebudowy indeksów, jedna procedura składowana zaczyna limit czasu dla każdego klienta wywołującego ją. Inne procedury przechowywane przy użyciu tych samych tabel nie miały żadnych problemów. Kiedy odkryłem problem, mogłem złagodzić wszystkie limity czasu i zawiesić procesy, zmieniając procedurę przechowywaną, aby natychmiast powrócić. Kiedy ponownie zmieniłem procedurę przechowywaną, aby zachowywać się normalnie, problemy pojawiały się natychmiast. Rozumiem, że zmiana procedury przechowywanej zmusiła ją do rekompilacji, ale to nie naprawiło.

Ostatecznie całkowicie upuściłem i ponownie utworzyłem procedurę z oryginalnym kodem, a problem został rozwiązany.

Ta procedura i stosowany przez nią schemat były całkowicie stabilne przez wiele miesięcy. Sama procedura jest dość prosta:

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 

Choć procedura zawiśnie i czas się z czymś takim:

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

Running identyczny wybierz w oknie zapytań wróci szybko i skutecznie:

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 

Jakieś pomysły, jak mogę temu zapobiec w przyszłości? Dziękuję Ci.

Edycja - Dodawanie wykonania planu ekranu Execution Plan of stored procedure above

Edycja - Dodawanie zapytanie użyte do wyświetlenia uruchomionych procesów. Było wiele, zgadując około 150, w stanie zawieszenia i wszyscy byli za tą samą procedurą przechowywaną - uspActivityGet. Procent danych IO został również przekroczony przez cały czas, gdy normalnie wynosi 20-40% w godzinach szczytowego zapotrzebowania. Nie pamiętam, jaki był typ oczekiwania. Oto zapytanie użyte do wyświetlenia tego.

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 

Edytuj - To się powtórzyło dziś wieczorem. Oto plan wykonania tej samej procedury podczas emisji. Po upuszczeniu i ponownym utworzeniu procedury plan wykonania powrócił do normy i problem został rozwiązany.

Podczas wydania, sp_executesql z identycznym zapytaniem zajęło około 5 minut i wierzę, że jest reprezentatywne dla tego, co się dzieje. Wystąpiło około 50 przypadków uspActivityGet zawieszonych z typem oczekiwania SLEEP_TASK lub IO_QUEUE_LIMIT.

Być może następnym pytaniem jest, dlaczego odbudowy indeksu lub inne nocne konserwacja robi to do planu wykonania?

enter image description here

+0

inne procedury, które nie mają problemów, korzystają z tych samych połączeń? może różne procedury wykorzystują różne indeksy? czy 'd.DatabaseId' jest indeksowany? czy wskazówki "NOLOCK" są wymagane? może indeksowanie problemów jest ukryte przez tę podpowiedź? co się stanie, jeśli uruchomisz zapytanie SSMS, gdy procedura się nie powiedzie? – Paolo

+0

@Paolo z uruchomieniem identycznej instrukcji SELECT w oknie zapytania powróci szybko i pomyślnie. – RJBreneman

+0

Czy jesteś w stanie stwierdzić, czy proc jest zablokowany lub robi coś przez bardzo długi czas lub coś innego? Gdy podasz identyfikator GUID jako stałą w zapytaniu, zmienia on sposób, w jaki SQL Server kosztuje zapytanie, aby test nie uruchamiał obu zapytań w ten sam sposób. Spróbuj przetestować za pomocą sp_executesql N '- twoje zapytanie', N '@ databaseid uniqueidentifier', '--your param' i sprawdź, czy nadal działa szybko lub grzęźnie. Podziel się także swoimi planami wykonawczymi, abyśmy mogli zobaczyć, co SQL Server myślał – SQLmojoe

Odpowiedz

1

Ślady są zapytania i kłopotliwego planu wykonania. Patrz: Poor Performance with Parallelism and Top

Normalny plan wykonania wydaje się dość wydajny i nie powinien być ponownie rekompilowany, dopóki nie zmieni się odpowiedni schemat. Chcę również uniknąć równoległości w tym zapytaniu. Dodałem dwie następujące opcje do zapytania o zapewnienie w obu punktach i wszystko znowu jest szczęśliwe.

OPTION (KEEPFIXED PLAN, MAXDOP 1) 
+0

Dobrze, że to naprawiłeś =) –