Předmluva
Existuje informační systém, který spravuji. Systém se skládá z následujících komponent:
1. Databáze MS SQL Server
2. Serverová aplikace
3. Klientské aplikace
Tyto informační systémy jsou instalovány na několika objektech. Informační systém aktivně využívá 24 hodin denně 2 až 20 uživatelů najednou na každém objektu. Běžnou údržbu tedy nemůžete provádět najednou. Musím tedy „rozložit“ defragmentaci indexu SQL Serveru během dne, spíše než defragmentovat všechny potřebné fragmentované indexy jedním tahem. To platí i pro ostatní operace.
Vlastnost automatické aktualizace statistik se nastavuje ve vlastnostech databáze. Kromě toho jsou statistiky aktualizovány na defragmentovaném indexu.
Problém
Asi před rokem jsem narazil na následující problém:
Čas od času probíhaly všechny dotazy pomalu. Je pozoruhodné, že doba zpoždění byla náhodná. Stalo se to u každého objektu v náhodný den. Navíc, když jsem začal analyzovat, jak často ke zpoždění dochází (pomocí profileru), zjistil jsem, že k nim dochází každý den v náhodnou dobu. Uživatelé jim prostě nevěnují vždy pozornost, ale berou je jako jediné náhodné zpoždění a systém pak zase rychle funguje.
Řešení problému
Zkontroloval jsem všechny pomalu běžící dotazy. Nejpodivnější na tom bylo, že všechny dotazy probíhaly pomalu v náhodnou dobu, dokonce i ty nejjednodušší, jako je vytahování posledního záznamu z tabulky s několika tisíci řádky.
Dále jsem provedl následující kroky:
1. Analyzoval jsem protokoly MS SQL Server a Windows Server, ale nemohl jsem najít příčinu zpoždění.
2. Analyzoval jsem indexy (fragmentaci atd.), doplnil chybějící a odstranil nepoužívané.
3. Analyzoval jsem dotazy – některé dotazy byly vylepšeny.
4. Analyzoval jsem úlohy v SQL Agent a nemohl jsem je přiřadit k problému zpoždění.
5. Analyzoval jsem úkoly v Plánovači úloh a nemohl jsem je přiřadit k problému zpoždění.
6. Profiler ukázal výsledky, ale ne příčinu zpoždění.
7. Provedl jsem kontrolu zablokování – žádná dlouhá blokování nebyla odhalena.
V důsledku toho jsem strávil více než 3 měsíce neúspěšným hledáním důvodu občasných pomalu běžících dotazů. Odhalil jsem však zajímavou skutečnost — místo indikátoru Worker execute se u všech dotazů zvýšil indikátor Elapsed wait. Tato skutečnost ve mně vyvolala myšlenku, že s disky není něco v pořádku. Zkontroloval jsem je – vše bylo v pořádku.
Řešení
K mému překvapení jsem náhodou odhalil, že když se v aplikaci pomalu spouštěl dotaz, běžel rychle v SSMS. Jeden článek pomohl při řešení problému (alespoň naznačoval myšlenku).
Odstavec z článku:
V praxi je nejdůležitější možností SET ARITHABORT, protože výchozí hodnota této možnosti se liší pro aplikace a pro SQL Server Management Studio. To vysvětluje, proč můžete ve své aplikaci detekovat pomalu běžící dotaz a poté dosáhnout dobré rychlosti jeho spuštěním v SSMS. Aplikace používá plán, který byl vytvořen pro sadu hodnot, které se liší od skutečných správných hodnot. Zatímco pokud spustíte dotaz v SSMS, je velmi pravděpodobné, že mezipaměť ještě nemá plán provádění pro ARITHABORT ON, a proto SQL Server vytvoří plán pro vaše aktuální hodnoty.
Rozdíl ve spuštění byl způsoben parametrem SET ARITHABORT. Pro všechny dotazy prováděné v SSMS je tato možnost povolena a pro dotazy zvenčí (z aplikací) – zakázána. Nelze jej povolit ani jednoduchým dotazem na aplikace:
SET ARITHABORT ON;
Následoval bláznivý nápad – vymazání mezipaměti procedur v době zavěšení.
Pro následnou ruční kontrolu musím před dotaz v SSMS napsat následující prohlášení:
SET ARITHABORT OFF;
Budeme tak simulovat provoz aplikace. Když dotaz běžel dlouhou dobu, vymazal jsem mezipaměť procedur. A tohle vždy pomohlo. Před vymazáním mezipaměti procedur může dotaz běžet až 20–30 sekund a poté – 0 sekund.
Poté jsem provedl další experiment – čištění celé procedurální mezipaměti pro celou databázi každou hodinu přes SQL Agent:
--cleaning the cache by database id DBCC FLUSHPROCINDB (@db_id);
Poté všechny dotazy běžely velmi rychle (méně než 0,05 sekundy). Vyskytly se pouze některé výskyty do 5–10 sekund provádění, ale uživatelé nezaznamenali žádné zablokování. Aktualizace statistik navíc nezlepšila výsledky, takže jsem aktualizaci statistik zakázal.
Po několika dalších měsících studia jsem zjistil, že k občasnému zablokování dochází, když mezipaměť spotřebovává vše na serveru a nezbývá žádné volné místo nebo je volná paměť, ale méně než 1 GB RAM nebo služba MS SQL Server zabírá veškerou přidělenou RAM (přes Správce úloh). Ale druhá událost se vyskytla pouze dvakrát za celou studii.
Faktem je, že do mezipaměti je zapsáno doslova vše, přičemž keš není vždy uvolněna včas. Problém s mezipamětí byl vyřešen pomocí programu EmptyStandbyList.exe.
Tuto aplikaci jsem nakonfiguroval přes Plánovač úloh tak, aby se spouštěla jednou za hodinu. Po všech provedených pracích již více než půl roku nedochází k žádnému zablokování dotazů na všech objektech.
Jediné, co zůstává nejasné, jsou ojedinělé případy, kdy jeden dotaz jednou za měsíc v náhodný den a v náhodný čas zavěsí na 5-10 sekund. Takové případy byly 4 a pouze na dvou objektech za půl roku, kdy služba MS SQL Server na krátkou dobu zabírá veškerou alokovanou paměť.
V zásadě není třeba pátrat hlouběji, protože uživatelé si nevšimnou žádného zasekávání a vše funguje dobře, ale pokud by někoho napadlo, budu vděčný za sdílení.
Tento článek byl napsán, aby pomohl těm, kteří se s takovými problémy setkávají, protože jsem na internetu nenašel vyčerpávající odpověď a strávil jsem spoustu času studiem problému a hledáním řešení.
Viz také:
- Implementace indikátoru výkonu SQL Server pro dotazy, uložené procedury a spouštěče
- Automatizace defragmentace indexu v databázi MS SQL Server
Užitečný nástroj:
dbForge Query Builder pro SQL Server – umožňuje uživatelům rychle a snadno vytvářet složité SQL dotazy prostřednictvím intuitivního vizuálního rozhraní bez ručního psaní kódu.