Příručka ve formátu PDF
1. Task Manager – kontrola CPU
Windows Server 2016
Windows Server 2008
- Na záložce „Details“ v „Task Manageru“ seřaďte spuštěné procesy sestupně podle sloupečku „CPU“ a zjistěte, který proces způsobuje neobvyklé vytížení CPU.
1.1. CPU je vytížené permanentně na 100 %
- Permanentní vytížení CPU může značit zacyklení webové aplikace, konzolové aplikace nebo služby, které je způsobené chybou ve zdrojovém kódu aplikace.
- Permanentní vytížení CPU procesem „w3wp.exe“ může značit zacyklení aplikačního poolu resp. chybu v některé z webových aplikací. Podle PID procesu „w3wp.exe“ je nutné v IIS dohledat příslušný aplikační pool, a identifikovat webové aplikace, které jsou tímto aplikačním poolem obsluhované.
- Permanentní vytížení CPU procesem „firebird.exe“ může značit buď špatně navržené SQL dotazy, které neúměrně vytěžují databázový server Firebird, nebo dlouhodobě narůstající zátěž databázového serveru, kterou je nutné řešit hardwarovým navýšením počtu jader procesoru.
- Permanentní vytížení CPU procesem „sqlserver.exe“ může značit buď špatně navržené SQL dotazy, které neúměrně vytěžují databázový server MSSQL, nebo dlouhodobě narůstající zátěž databázového serveru, kterou je nutné řešit hardwarovým navýšením počtu jader procesoru.
1.2. Vytížení CPU osciluje kolem hranice 70 % a výše
- Vyšší vytížení CPU procesem „w3wp.exe“ může značit neoptimální algoritmy v některé z webových aplikací. Podle PID procesu „w3wp.exe“ je nutné v IIS dohledat příslušný aplikační pool, a identifikovat webové aplikace, které jsou tímto aplikačním poolem obsluhované.
- Vyšší vytížení CPU procesem „firebird.exe“ může značit buď špatně navržené SQL dotazy, které neúměrně vytěžují databázový server Firebird, nebo dlouhodobě narůstající zátěž databázového serveru, kterou je nutné řešit hardwarovým navýšením počtu jader procesoru.
- Vyšší vytížení CPU procesem „sqlserver.exe“ může značit buď špatně navržené SQL dotazy, které neúměrně vytěžují databázový server MSSQL, nebo dlouhodobě narůstající zátěž databázového serveru, kterou je nutné řešit hardwarovým navýšením počtu jader procesoru.
1.2.1. Příklady neoptimálních algoritmů
- For cykly, které v každé iteraci volají SQL dotaz – řešením je hromadné načtení všech dat před samotným for cyklem, a následná indexace těchto dat do objektu „Dictionary“. Tento postup je detailně popsán v samostatné příručce Externí funkce.
- Generování velkých souborů ve formátu PDF či XLSX pomocí knihoven „Aspose“ – řešením je hardwarové navýšení počtu jader.
- Zpracovávání obrázků ve vysokém rozlišení – řešením je hardwarové navýšení počtu jader.
- Neoptimální algoritmy jsou často umístěné v jedné z externích funkcí, nebo mohou být způsobené tiskem do tiskových šablon. V obou případech je důležité zkontrolovat report skriptů (total_worker_time) a externích funkcí (total_worker_time), ve kterém se dlouhé časy trvání skriptů nebo externích funkcí zobrazí na předních příčkách reportu.
1.3. Vytížení CPU osciluje pod hranicí 50 %
Tento stav je normální.
2. Task Manager – kontrola paměti
Windows Server 2016
Windows Server 2008
- Na záložce „Details“ v „Task Manageru“ seřaďte spuštěné procesy sestupně podle sloupečku „Memory (private working set)“ a zjistěte, který proces způsobuje neobvyklé vytížení paměti.
2.1. Paměť je vytížená permanentně na 100 %
- Permanentní vytížení paměti procesem „w3wp.exe“ může značit neoptimální algoritmy nebo načítání příliš velkého množství dat z databáze v některé z webových aplikací. Podle PID procesu „w3wp.exe“ je nutné v IIS dohledat příslušný aplikační pool, a identifikovat webové aplikace, které jsou tímto aplikačním poolem obsluhované. U všech těchto aplikací je nutné zapnout logování do databáze a měření spotřeby paměti v nastavení NET Genia viz kapitola „Logování NET Genia a vyhodnocení logů”.
- Permanentní vytížení paměti procesem „firebird.exe“ může značit buď špatně navržené SQL dotazy, které neúměrně vytěžují databázový server Firebird, nebo dlouhodobě narůstající zátěž databázového serveru, kterou je nutné řešit hardwarovým navýšením paměti.
- Permanentní vytížení paměti procesem „sqlserver.exe“ může značit buď špatně navržené SQL dotazy, které neúměrně vytěžují databázový server MSSQL, nebo dlouhodobě narůstající zátěž databázového serveru, kterou je nutné řešit hardwarovým navýšením paměti.
- Permanentní vytížení paměti procesem „sqlserver.exe“ mimo jiné značí, že jedna z instancí (většinou ta výchozí) nemá nastavený limit pro využívání paměti, což následně znemožňuje správný chod jak operačního systému, tak ostatních aplikací. Každá instance serveru MSSQL by měla mít vždy nastavený limit pro využívání paměti na bezpečnou mez, například pouze na 80 % z celkové paměti, aby i operační systém a ostatní aplikace měly dostatek prostoru pro svou činnost.
2.2. Vytížení paměti se pohybuje mezi 60 % a 99 %
- Vysoké vytížení paměti procesem „w3wp.exe“ může značit načítání příliš velkého množství dat z databáze v některé z webových aplikací. Podle PID procesu „w3wp.exe“ je nutné v IIS dohledat příslušný aplikační pool, a identifikovat webové aplikace, které jsou tímto aplikačním poolem obsluhované. U všech těchto aplikací je nutné zapnout logování do databáze a měření spotřeby paměti v nastavení NET Genia viz kapitola „Logování NET Genia a vyhodnocení logů”.
- Je vhodné zvážit hardwarové navýšení paměti především kvůli jednorázovému spouštění náročnějších úloh na paměť.
- Je nutné zkontrolovat nastavení instance serveru MSSQL, zda má nastavený limit pro využívání paměti.
2.3. Vytížení paměti se pohybuje pod hranicí 50 %
Tento stav je normální.
3. Čekající aktualizace operačního systému Windows
- Na aplikačním i databázovém serveru zkontrolujte frontu čekajících aktualizací, u kterých je nutné dokončit instalaci. Tyto aktualizace mohou čekat na pozadí, a brát paměť celému serveru, přestože v Task Manageru to vypadá, že má server volné paměti dostatek. Ten následně nemá prostředky pro běžné spouštění a běh procesů, a kolabují jak běžné aplikace na aplikačním serveru, tak i databázový server. Typicky se tento stav na databázovém serveru projevuje tím, že si instance MSSQL alokuje například pouze 200MB, přestože má nastavený limit na daleko více, nebo nemá nastavený limit na alokovanou paměť vůbec.
4. Debug Diagnostic Tool
- V kritických situacích je nutné ukončit jednotlivé procesy v „Task Manageru“. Před tímto krokem je užitečné vytvořit „memory dump“ daného procesu, který může být následně analyzován pomocí nástroje „Debug Diagnostic Tool“, a dokáže odhalit jak zacyklené algoritmy, tak důvod zahlcení paměti.
- Zjednodušený postup pro práci s „memory dumpy“ je uveden v souboru „Config \Tools\MemoryDumps.txt “ každého NET Genia:
1) Download and install Debug Diagnostic Tool v2 Update 2 (https://www.netgenium.com/download/DebugDiagx64.msi)
2) Locate memory dumps (C:\Users\abc\AppData\CrashDumps)
3) Run DebugDiag
4) Default Analysis / CrashHangAnalysis
5) Add Data Files
6) Start Analysis
5. Tento počítač – kontrola disků
- Došlé místo na disku často znamená nenávratné ztráty dat spojené narušením konzistence databází. Nejrychlejší cesta, jak uvolnit místo na disku, je smazat logové soubory nebo zálohy databází a souborů.
- Program „TDP x-Ray“ je ideální nástroj na detailní analýzu zaplnění disků jednotlivými adresáři a soubory.
- Mezi logové soubory patří jak logové soubory samotného IIS umístěné ve výchozím adresáři „C:\inetpub \logs\LogFiles” , tak logové soubory konkrétních NET Genií – adresář „Logs“ každého NET Genia.
- Zálohy databází jsou často umístěné v adresáři „Backup“ každého NET Genia, nebo v adresáři „E: \BackupServer “.
- IIS má ve výchozím nastavení zapnuté protokolování provozu webových aplikací, které je nutné co nejdříve vypnout. Současně s tím je důležité smazat již existující logy, které se ve výchozím nastavení ukládají do adresáře „C:\inetpub \logs\LogFiles “. Přesné umístění těchto logů zjistěte z konkrétního nastavení IIS podle následujícího postupu.
- Přejděte do nastavení IIS a vyberte nejvyšší uzel vašeho serveru/počítače (například „OFFICE“ / „TOMAS-PC“), aby se nastavení propsalo i na další podřízené uzly, a v sekci „IIS“ vyberte „Logging“ / „Protokolování“.
- Na panelu „Akce“ na pravé straně okna poté klikněte na „Zakázat“. Tím se vypne logování povozu pro uzel vašeho serveru/počítače.
6. Performance Manager – kontrola diskových operací
- Na záložce „Performance“ v „Task Manageru“ klikněte na odkaz „Open Resource Monitor“.
- Na záložce „Disk“ v „Resource Monitoru“ seřaďte diskové aktivity sestupně podle sloupečku „Write“ a zjistěte, které soubory – databáze Firebird nebo MSSQL – vykazují neobvyklé zápisy na disk.
7. RunningQueries.exe
- Aplikace „RunningQueries.exe“ je umístěna v adresáři „bin“ každého NET Genia, a slouží pro vyhodnocení aktuálně zpracovávaných databázových dotazů. Spuštění této aplikace vytváří logový soubor „RunningQueries.htm“ v adresáři „Logs“, a zároveň tento logový soubor otevírá. Zpracovávané dotazy zmíněné v tomto logovém souboru mohou být důvodem snížení výkonu databázového serveru. Zároveň mohou sloužit k identifikaci databáze, ve které dochází k výkonnostním problémům.
8. SQL Server – Activity Monitor
- Spusťte „SQL Server Management Studio“ a klikněte na ikonu „Activity Monitor“.
- Na záložce „Recent Expensive Queries“ identifikujte seznam naposledy spuštěných náročných databázových dotazů. Tyto dotazy mohou zároveň sloužit k identifikaci databáze, ve které dochází k výkonnostním problémům.
9. SQL Server – Top Queries by Total CPU Time
- Spusťte „SQL Server Management Studio“, klikněte pravým tlačítkem myši na nejvyšší uzel v „Object Exploreru“, a vyberte „Reports / Standard Reports / Performance – Top Queries by Total CPU Time“.
- V tomto reportu identifikujte seznam databázových dotazů, které nejvíce zatěžují databázový server. Tyto dotazy mohou zároveň sloužit k identifikaci databáze, ve které dochází k výkonnostním problémům.
- Jakmile dojde k identifikaci databáze, ve které dochází k výkonnostním problémům, je výhodnější spustit konkrétní NET Genium, a nechat si zobrazit report „dm_exec_query_stats (total_worker_time)“. Tento report zobrazuje identický seznam databázových dotazů, které nejvíce zatěžují databázový server, a navíc nabízí možnost identifikace ovládacího prvku, který databázový dotaz spouští (odkaz „…“).
- SQL Server nabízí také report „Top Queries by Average CPU Time“, který má ekvivalent v NET Geniu pod reportem „dm_exec_query_stats (average_worker_time)“.
- Obecně je doporučené reporty procházet v následujícím pořadí:
- dm_exec_query_stats (total_worker_time) – v tomto reportu jsou na prvních místech jak databázové dotazy, které mohou mít rozumný čas zpracování dotazu, ale spouští se příliš často, tak databázové dotazy, které se spouští v rozumných intervalech, ale mají dlouhý čas zpracování.
- dm_exec_query_stats (execution_count) – v tomto reportu jsou na prvních místech databázové dotazy, které se spouští často, a proto je u těchto dotazů důležité posoudit „average_worker_time“.
- dm_exec_query_stats (average_worker_time) – v tomto reportu jsou na prvních místech databázové dotazy, které mají dlouhý čas zpracování jednotlivých dotazů.
- Typická chyba nesprávně navrženého dotazu, který je spouštěn velmi často, a nemá nastavený index na sloupečku „ng_url“.
10. Logování NET Genia a vyhodnocení logů
- Kroky uvedené v předchozích kapitolách by měly sloužit k identifikaci databáze, ve které dochází k výkonnostním problémům.
- Zapněte logování v nastavení NET Genia výběrem „Do databáze”. Řešíte-li zvýšené vytížení paměti, zapněte také „Měřit spotřebu paměti”. Detailní popis nastavení NET Genia je uveden v samostatné příručce „Nastavení NET Genia”.
- Logy vyhodnoťte pomocí reportů, a identifikujte nahlížecí stránky, editační formuláře, databázové dotazy, skripty nebo externí funkce, které trvají nejdéle. Detailní popis reportů je uveden v samostatné příručce Reporty.
- Nahlížecí stránky (average_worker_time)
- Nahlížecí stránky (total_worker_time)
- Editační formuláře (average_worker_time)
- Editační formuláře (total_worker_time)
- Databázové dotazy (average_worker_time)
- Databázové dotazy (total_worker_time)
- Skripty (average_worker_time)
- Skripty (total_worker_time)
- Externí funkce (average_worker_time)
- Externí funkce (total_worker_time)
11. Úpravy SQL dotazů a programového kódu
- Nejčastějším důvodem problémů s výkonem jsou nevhodně navržené databázové dotazy, nebo neefektivní načítání dat z databáze. Ve většině případů stačí správně nastavit indexy na sloupečky v databázi, nebo změnit způsob joinování databázových tabulek. Daleko pracnější, avšak stejně důležité, je změnit způsob načítání dat z databáze tak, aby se do databáze posílalo co nejméně dotazů, a vždy všechny dotazy dané úlohy spouštět pouze v rámci jediného připojení do databáze.
11.1. Indexy
- Indexy slouží pro zrychlení databázových dotazů, nejčastěji pro zrychlení příkazů SELECT.
Kde se index nastavuje
- Zapínání/vypínání indexů u sloupců „pid“ a „pform“ se provádí na záložce „Administrace“ ve vlastnostech editačního formuláře.
- Zapínání/vypínání indexů u všech ostatních sloupců databázové tabulky se provádí ve vlastnostech ovládacího prvku na záložce „Administrace“.
Kdy a proč nastavit index
- Při řešení optimalizace chodu databáze je důležité dodržovat základní pravidlo, že musí být indexován každý sloupec, který se vyskytuje v podmínkách joinů buď na levé, nebo na pravé straně podmínky. Všechny ostatní joiny mohou být zapínány/vypínány až po nějaké době chodu aplikace, kdy se databáze postupně naplňuje daty. V průběhu času se potřeby nastavení indexů mění, a to v prvé řadě podle narůstajícího množství záznamů v jednotlivých databázových tabulkách, a v důsledku toho i podle způsobu čtení těchto dat.
- Na levé straně podmínky joinu se často používá sloupeček (ID), což je primární klíč databázové tabulky. Tento sloupec je indexován automaticky.
- Na pravé straně podmínky joinu se často používá cizí klíč resp. ovládací prvek ForeignKey. Index na tomto sloupci je automaticky zapnutý při vytvoření ovládacího prvku, je však možné ho dodatečně vypnout.
- Postupné zapínání/vypínání indexů musí vycházet ze základní podstaty indexů – indexovat daný sloupec má smysl pouze v případě, že se hodnota sloupce vyhodnocuje pomocí operátoru „rovná se“, „je definováno“ nebo „není definováno“.
- Před zahájením každého ladění indexů je nutné zapnout logování NET Genia do databáze.
Reporty
- NET Genium obsahuje reporty s analýzou všech indexů v databázi spolu s doporučením, kde index zapnout. V případě databáze MSSQL obsahuje také reporty s fragmentací indexů a statistikou využívání indexů. Tyto reporty jsou detailně popsány v samostatné příručce „Reporty“, kapitola „Indexy“.
- V reportu „Joiny“ je důležité vyhledat výskyt třech vykřičníků „!!!“. Vykřičníky upozorňují na sloupce použité v podmínkách joinů, které nemají zapnutý index. U těchto sloupců je důležité index neprodleně zapnout.
- Všechny ostatní záznamy v reportu „Joiny“ mají pouze informativní charakter, a upozorňují na sloupce používané v podmínkách databázových dotazů, u kterých v budoucnu pravděpodobně bude nutné index zapnout.
- Report „Joiny“ nezohledňuje dotazy, které se používají uvnitř zdrojových kódů externích funkcí nebo konzolových aplikací. Obsahuje tedy pouze dotazy navržené v návrháři databázových dotazů.
Jak fungují indexy
- Pochopení principu indexů je klíčové pro správné navržení indexů v databázi. Následující příklad v jazyce C# demonstruje hledání záznamů v databázi pomocí pomalého sekvenčního procházení, a následně pomocí rychlého hledání za pomoci slovníku.
- Sekvenční procházení je analogií pro situaci, kdy databázový server nemá k dispozici index, a proto je nucený databázové záznamy procházet všechny – vždy jeden po druhém – a pokusit se najít shodu na základě vyhledávacích kritérií.
- Používání slovníku je analogií pro situaci, kdy databázový server má k dispozici index na daném sloupci, a hledá všechny záznamy, které mají v daném sloupci uloženou jednu konkrétní hodnotu. U všech ostatních vyhledávacích kritérií – jiných než shoda na jednu konkrétní hodnotu – je nutné použít sekvenční procházení, a není tedy možné použít index.
using System.Data;
using System.Diagnostics;
// SELECT * FROM ng_tabulka WHERE ng_tb IN ('10', '100', '1000', '10000', abc')
string[] search = new string[] { "10", "100", "1000", "10000", "abc" };
DataTable data = new DataTable();
data.Columns.Add("ng_tb");
for (int i = 0; i < 5000000; i++)
{
data.Rows.Add(i.ToString());
}
Stopwatch sw1 = Stopwatch.StartNew();
foreach (string s in search) Console.WriteLine(s + ": " + Find(data, s));
Console.WriteLine("Sekvenční procházení: " + sw1.Elapsed);
Console.WriteLine();
Dictionarydictionary = new Dictionary ();
foreach (DataRow row in data.Rows)
{
dictionary.Add(row["ng_tb"].ToString(), row);
}
Stopwatch sw2 = Stopwatch.StartNew();
foreach (string s in search) Console.WriteLine(s + ": " + Find(dictionary, s));
Console.WriteLine("Slovník: " + sw2.Elapsed);
Console.WriteLine();
Console.ReadLine();
private static bool Find(DataTable data, string search)
{
foreach (DataRow row in data.Rows) if (row["ng_tb"].ToString() == search) return true;
return false;
}
private static bool Find(Dictionarydictionary, string search)
{
if (dictionary.ContainsKey(search)) true;
return false;
}
11.2. Joiny
LEFT JOIN
- SELECT * FROM ng_faktura LEFT JOIN ng_polozka ON ng_polozka.pid = ng_faktura.id
- Načtení všech faktur spolu se všemi položkami
- Ve výsledné tabulce jsou faktury zduplikované tolikrát, kolik má každá faktura položek
- Ve výsledné tabulce jsou i faktury, které nemají žádnou položku (všechny sloupce z přijoinované tabulky položek mají ve výsledné tabulce uloženou databázovou hodnotu NULL)
- SELECT * FROM ng_faktura LEFT JOIN ng_polozka ON ng_polozka.pid = ng_faktura.id WHERE ng_polozka.id IS NULL
- Načtení všech faktur, které nemají žádnou položku
- Ve výsledné tabulce jsou pouze faktury, které nemají žádnou položku (všechny sloupce z přijoinované tabulky položek mají ve výsledné tabulce uloženou databázovou hodnotu NULL)
- SELECT * FROM ng_faktura LEFT JOIN ng_polozka ON ng_polozka.pid = ng_faktura.id WHERE ng_polozka.ng_cena > 100
- Načtení všech faktur, které mají položku s cenou větší než 100
- Ve výsledné tabulce jsou faktury zduplikované tolikrát, kolik má každá faktura položek s cenou větší než 100
- Tento dotaz je klasickým příkladem „LEFT JOIN + Podmínka“, u kterého je výhodné změnit pomalejší LEFT JOIN za rychlejší INNER JOIN.
INNER JOIN
- SELECT * FROM ng_faktura INNER JOIN ng_polozka ON ng_polozka.pid = ng_faktura.id
- Načtení všech faktur, které mají alespoň jednu položku
- Ve výsledné tabulce jsou faktury zduplikované tolikrát, kolik má každá faktura položek
- Ve výsledné tabulce jsou pouze faktury, které mají alespoň žádnou položku
11.3. Nejčastější chyby v databázových dotazech
- SELECT * – databázový dotaz by nikdy neměl obsahovat hvězdičku jako zástupný znak pro všechny sloupce zdrojové databázové tabulky, i všech sloupců všech přijoinovaných tabulek, ale vždy by měl obsahovat výčet načítaných sloupců oddělených čárkou.
- Načítání stringů neomezené délky (TextArea, RichTextBox, MultiListBox) způsobuje značné zpomalení zpracování databázového dotazu především na databázovém serveru Firebird. Tyto sloupce by se měly načítat pouze v nejnutnějších případech.
- Detailní popis způsobu načítání dat z databáze pomocí C# včetně příkladů je uveden v samostatné příručce Externí funkce, kapitola „Čtení dat z databáze“.
11.4. Nejčastější chyby při joinování
- Nedodržování základního pravidla, že musí být indexován každý sloupec, který se vyskytuje v podmínkách joinů buď na levé, nebo na pravé straně podmínky.
- Joiny definované v návrháři databázových dotazů jsou často buď úplně zbytečné, protože se ve výsledku nijak nepoužívají sloupečky načtené z přijoinované databázové tabulky, používají pomalejší „LEFT“ namísto rychlejšího „INNER“ v případech, kdy je „LEFT“ zbytečný, nebo používají „LEFT“ ve spojení s podmínkou databázového dotazu viz příručka Reporty, kapitola „Databázové dotazy (LEFT JOIN + Podmínka)“.
- Ve chvíli, kdy se k sobě joinují objemné databázové tabulky, nebo je joinů až příliš, je nutné zcela změnit logiku načítání dat, a nákladný databázový dotaz s mnoha joiny rozdělit do více jednodušších databázových dotazů.
11.5. SQL Server Database Engine Tuning Advisor – ladění SQL dotazů
- SQL Server obsahuje užitečný nástroj na ladění databázových dotazů – SQL Server Database Engine Tuning Advisor. Zjednodušený postup pro ladění databázových dotazů je uveden v souboru „Config\Tools\TunningQueries.txt“ každého NET Genia:
1) Run SQL Server Management Studio
2) Right click on the instance name and select 'Reports / Standard Reports / Performance - Top Queries by Total CPU Time'
3) Identify top queries with constants in a condition that can be improved with indexes
4) Right click on the background of the report and select 'Print / Excel'
5) Open printed Excel file
6) Create 'netgenium.sql' file and insert top queries using the following syntax:
use netgenium
go
SELECT ...
SELECT ...
7) Run SQL Server Database Engine Tuning Advisor
8) Click 'Start New Session'
9) Select 'File' as a 'Workload' and browse for 'netgenium.sql'
10) Mark 'netgenium' database
11) Click 'Start Analysis'
12) Analyze 'Recommendations' tab
13) Create new indexes as recommended