Mam za zadanie poprawić wydajność () i jest to mój pierwszy rzeczywisty tuning wydajności) raportowania przechowywanej procedury, która jest wywoływana przez front-end SSRS i procedura przechowywana trwa obecnie około 30 sekund do uruchom na największej ilości danych (w oparciu o filtry ustawione z frontendu raportu).Ulepszanie czasu wykonywania przechowywanych procedur - dostrajanie tabel tymczasowych?
Ta procedura składowana zawiera zestawienie 19 zapytań, z których większość przekształca dane z początkowego (tradycyjnego) formatu z tabel podstawowych do znaczącego zestawu danych, który ma być wyświetlany po stronie biznesowej.
Utworzyłem zapytanie oparte na kilku DMV-ach, aby dowiedzieć się, które są najbardziej zasobochłonne zapytania z procedury składowanej (mały fragment poniżej) i znalazłem jedno zapytanie, które trwa około 10 sekund, średnia, do uzupełnienia.
select
object_name(st.objectid) [Procedure Name]
, dense_rank() over (partition by st.objectid order by qs.last_elapsed_time desc) [rank-execution time]
, dense_rank() over (partition by st.objectid order by qs.last_logical_reads desc) [rank-logical reads]
, dense_rank() over (partition by st.objectid order by qs.last_worker_time desc) [rank-worker (CPU) time]
, dense_rank() over (partition by st.objectid order by qs.last_logical_writes desc) [rank-logical write]
...
from sys.dm_exec_query_stats as qs
cross apply sys.dm_exec_sql_text (qs.sql_handle) as st
cross apply sys.dm_exec_text_query_plan (qs.plan_handle, qs.statement_start_offset, qs.statement_end_offset) as qp
where st.objectid in (object_id('SuperDooperReportingProcedure'))
, [rank-execution time]
, [rank-logical reads]
, [rank-worker (CPU) time]
, [rank-logical write] desc
Teraz ta kwerenda jest nieco dziwne w tym sensie, że plan wykonania pokazuje, że pokazuje, że większość prac (~ 80%) odbywa się podczas wstawiania danych do lokalnej tabeli tymczasowej, a nie wtedy, gdy odpytywanie innych tabel, z których pobierane są dane źródłowe, a następnie manipulowane. (Poniżej zrzut ekranu jest z programu SQL Sentry Plan Explorer)
Również pod względem szacunków rzędu, plan wykonania ma daleko szacunki dotyczące tego, w tym sensie, że istnieją tylko 4218 wiersze wstawione do lokalnej tabela tymczasowa w przeciwieństwie do wierszy ~ 248k, które plan wykonania uważa za przeniesienie do lokalnej tabeli tymczasowej. Tak więc, ze względu na to, myślę "statystyki", ale czy nadal ma to znaczenie, jeśli ~ 80% pracy jest rzeczywistą wstawić do stołu?
Jednym z moich pierwszych zaleceń było ponowne napisanie całego procesu i procedury przechowywanej, tak aby nie uwzględniać przenoszenia i przekształcania danych do przechowywanej procedury składowania i przeprowadzania transformacji danych co noc w niektórych utrwalonych tabelach (dane w czasie rzeczywistym nie są wymagane, tylko istotne dane do końca poprzedniego dnia). Ale strona biznesowa nie chce zainwestować czasu i zasobów w przeprojektowanie tego, a zamiast tego "sugeruje", że robię dostrajanie wydajności w sensie znajdowania gdzie i jakie indeksy mogę dodać, aby przyspieszyć to.
Nie sądzę, że dodanie indeksów do tabel podstawowych poprawi wydajność raportu, ponieważ większość czasu potrzebnego do uruchomienia kwerendy polega na zapisaniu danych do tabeli tymczasowej (co z mojej wiedzy spowoduje trafienie tempdb, co oznacza, że zostaną zapisane na dysk -> zwiększony czas z powodu opóźnienia we/wy).
Ale mimo to, jak już wspomniałem, jest to moje pierwsze zadanie polegające na dostrajaniu osiągów i starałem się czytać jak najwięcej w związku z tym w ciągu ostatnich kilku dni i są to moje dotychczasowe wnioski, ale Chciałbym poprosić o radę szerszej publiczności i mam nadzieję, że zdobędę więcej informacji i zrozumienie, co mogę zrobić, aby ulepszyć tę procedurę.
W kilku jasnych pytań byłbym wdzięczny, gdyby mógł odpowiedzieć to:
- Czy jest coś błędnie, co powiedziałem powyżej (w moim zrozumieniu dB lub moich założeń)?
- Czy to prawda, że dodanie indeksu do tabeli tymczasowej spowoduje zwiększenie czasu wykonania, ponieważ tabela (i powiązany z nią indeks (y) są/są odbudowywane po każdym wykonaniu)?
- Czy w tym scenariuszu może być coś jeszcze, bez konieczności ponownego pisania procedury/zapytań i można to zrobić tylko za pomocą indeksów lub innych metod strojenia? (Czytałem kilka nagłówków artykułów, które można również "dostroić tempdb", ale jeszcze nie dostałem szczegółów).
Każda pomoc jest bardzo doceniana i jeśli potrzebujesz więcej informacji, chętnie opublikuję.
Update (02 sierpnia 2016)
Zapytanie o którym mowa, jest (częściowo) poniżej. Brakuje jeszcze kilka kruszywa kolumny i odpowiadające im linie w sekcji GROUP BY
:
select
b.ProgramName
,b.Region
,case when b.AM IS null and b.ProgramName IS not null
then 'Unassigned'
else b.AM
end as AM
,rtrim(ltrim(b.Store)) Store
,trd.Store_ID
,b.appliesToPeriod
,isnull(trd.countLeadActual,0) as Actual
,isnull(sum(case when b.budgetType = 0 and b.budgetMonth between @start_date and @end_date then b.budgetValue else 0 end),0) as Budget
,isnull(sum(case when b.budgetType = 0 and b.budgetMonth between @start_date and @end_date and (trd.considerMe = -1 or b.StoreID < 0) then b.budgetValue else 0 end),0) as CleanBudget
...
into #SalvesVsBudgets
from #StoresBudgets b
left join #temp_report_data trd on trd.store_ID = b.StoreID and trd.newSourceID = b.ProgramID
where (b.StoreDivision is not null or (b.StoreDivision is null and b.ProgramName = 'NewProgram'))
group by
b.ProgramName
,b.Region
,case when b.AM IS null and b.ProgramName IS not null
then 'Unassigned'
else b.AM
end
,rtrim(ltrim(b.Store))
,trd.Store_ID
,b.appliesToPeriod
,isnull(trd.countLeadActual,0)
Nie jestem pewien, czy jest to rzeczywiście pomocne, ale ponieważ @kcung o to, dodałem informację.
Ponadto, aby odpowiedzieć na jego pytania:
- tabele tymczasowe nie mają indeksy na nich
- RAM rozmiar: 32 GB
Update (03 sierpnia 2016):
Próbowałem sugerować @ kcung, aby przenieść instrukcje CASE
z kwerendy generowania agregatów i niefortunne ogólnie rzecz biorąc, czas procedury nie poprawił się, zauważalnie, ponieważ wciąż waha się w zakresie od ± 0,25 do ± 1,0 sekundy (tak, zarówno niższy, jak i wyższy czas, niż oryginalna wersja procedury przechowywanej - ale zgaduję, że to jest spowodowane zmiennym obciążeniem na moim komputerze).
plan wykonania dla tego samego zapytania, ale zmodyfikowane w celu usuwania warunki CASE
, pozostawiając tylko agregaty SUM
jest teraz:
1. Zaktualizowano pytania, podając więcej szczegółów. –
2. Brak indeksów w tabelach tymczasowych. –
4. Czy myślisz o fragmentacji strony tutaj? –