Porady na temat diagnozowania „czasem” powolnego zapytania


20

Mam procedurę składowaną, która zwraca wyniki z widoku indeksowanego za pomocą indeksu obejmującego. Zwykle działa szybko (~ 10 ms), czasem może działać nawet do 8 sekund.

Oto przykład losowego wykonania (uwaga: to nie jest powolne, ale tekst zapytania jest taki sam, z wyjątkiem przekazywanej wartości):

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

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

(uwaga: dodałem OPTION (RECOMPILE)wskazówkę niedawno po kilku radach, ale to nie pomogło.

Oto indeks obejmujący (uwaga: widok ma również indeks klastrowany ListingId, który jest unikalny)

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

Włączyłem śledzenie profilera ze statystykami showplan XML.

Oto powolny (6 sekund) i odpowiedni plan: wprowadź opis zdjęcia tutaj

Wygląda dokładnie tak, jak się spodziewałem i jest taki sam plan, gdy zapytanie jest szybkie.

Oto powiększenie kosztownej części planu, jeśli to pomaga: wprowadź opis zdjęcia tutaj

Oto pełny schemat tabel widoku / kopii zapasowej, jeśli to pomaga: https://pastebin.com/wh1sRcbQ

Uwagi:

  • Indeksy zostały zdefragmentowane, statystyki są aktualne.
  • Pierwotnie zapytanie było wbudowane w widok, ale przeniosłem się do SPROC, aby spróbować ustabilizować. Nie pomogło
  • Dodanie WITH OPTION (RECOMPILE);podpowiedzi (nie działało, więc nie może być wąchanie parametru?)
  • Inne zapytania w systemie również czasami działają wolno i nie mają też żadnych oczywistych problemów w swoim planie.
  • Może być blokowany? Nie jestem pewien, jak to potwierdzić.

Jakieś pomysły na to, co mogę spróbować dalej?

Dzięki


1
Komentarze nie są przeznaczone do rozszerzonej dyskusji; ta rozmowa została przeniesiona do czatu . Wszyscy: skorzystaj z tego narzędzia do dalszej dyskusji na temat tego pytania.
Paul White mówi GoFundMonica

dany link nie działa. zapytanie proc jest proste, istnieje ogromna różnica między rzeczywistą a szacowaną liczbą wierszy, co stanowi problem, myślę, że problem leży w polu zapytania, myślę, że dane są niewystarczające, powinno być blisko
KumarHarsh

Czy próbowałeś uruchomić WhoIsActive (autor: Adam Machanic) podczas działania zapytania? whoisactive.com Zawiera informacje o zadaniach oczekujących, które powinny wskazać właściwy kierunek.
MJH,

Czy wyeliminowałeś coś zewnętrznego względem DB, które to powoduje? Być może jakaś inna aplikacja powodująca synchroniczne We / Wy do pamięci współdzielonej z DB?
Johan

Odpowiedzi:


2

Naprawdę nie sądzę, aby używanie tego OPTION (RECOMPILE)było skutecznym sposobem na wyeliminowanie możliwości wąchania parametrów.

Wykrywanie parametrów ma miejsce, gdy SQL jest mylony z określonym zapytaniem i myśli o swoim nowym, ponieważ widzi nowe parametry. Jest powolny, ponieważ wygenerowanie nowego planu wykonania zajmuje więcej czasu.

Wszystko, co robi ta opcja, zmusza SQL do tworzenia nowego planu za każdym razem, co jest prawie tym samym. Zamiast tego możesz rozważyć dodanie parametrów domyślnych za pomocą tej wskazówki:

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

Wybierając parametry domyślne, należy użyć zestawu reprezentatywnego statystycznie.
Wymusi to stosowanie tego samego planu za każdym razem i wyeliminuje możliwość wąchania parametrów. Gdy to zrobisz i określisz, że to nie pomogło, prawdopodobnie bezpiecznie można odrzucić wąchanie parametrów jako możliwą.


1

Być może spróbuj wymusić kolejność, więc prawdopodobnie zawsze zaczynasz od mniejszej tabeli (zmiennej). Jest to trudne z widokami ...

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

lub możesz wymusić sprzężenie pętli, jeśli ogólnie tak chcesz dołączyć zmienną tabeli do widoku, co również wymusi porządek ...

    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

Wpisz nazwę procedury Store w edytorze zapytań, a następnie wybierz proc. Sklepu. nazwa, a następnie wybierz opcję Wyświetl plan wykonania szacunkowego lub kliknij (Ctrl + L). poniżej obrazu tego.

Obraz wyświetlania szacowanego planu wykonania

następnie Plany wykonania są wyświetlane tuż obok karty Wiadomości na dole Edytora zapytań. następnie w zielone linie pokaż brakujące dane indeksu i kliknij je prawym przyciskiem myszy. Następnie otwórz nowe zapytanie w nowej karcie, a następnie utwórz INDEKS. wtedy Twoje zapytanie działa szybko.

Więc użyłem tej metody do zdiagnozowania zapytania, które pracuje wolno. a także istnieje tak wiele zapytań lub metod, których można użyć.

Plan wykonania ze szczegółami


-1

Jeśli uważasz, że problem polega na blokowaniu, zasugeruję, abyś użył optymistycznego poziomu izolacji transakcji Przeczytaj zatwierdzoną migawkę (pamiętaj, że spowoduje to obciążenie twojego tempDB).

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

Jeśli problem nie polega na blokowaniu odczytu / zapisu, możesz spróbować dodać indeksy do swojego widoku (najlepszy wybór indeksów zależy od selektywności danych)

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

1
Indeks, który sugerujesz, już istnieje IX_ListingSearchView_ForAPI(patrz skrypt w pytaniu).
Paul White mówi GoFundMonica

1
Hej, dzięki za odpowiedź. Jak już wspomniałem w moim pytaniu, chcę wiedzieć, na czym polega problem, zanim zastosuję poprawkę. W przeciwnym razie mógłbym przeoczyć prawdziwy problem. Moje pytanie dotyczy najpierw znalezienia problemu, a następnie prawidłowego rozwiązania.
RPM1984,

Czy możesz otrzymać to wolne zapytanie w swoim lokalnym środowisku? Jeśli to samo zapytanie czasami działa wolno, a czasem szybko, może to zależeć od parametrów wejściowych. Czy możesz podać liczbę logicznych odczytów i całkowitą liczbę wierszy zwróconych przez twoje wolne zapytanie.
Artashes Khachatryan

@ArtashesKhachatryan tak, czasami działa również lokalnie. Zaktualizowałem pytanie o plan wykonania. Zastanawiam się, czy jest to związane z powolnymi zapytaniami zwracającymi więcej wierszy niż szybkie, jak już powiedziałeś.
RPM1984
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.