sql >> Databáze >  >> RDS >> Database

Zachyťte varování plánu provádění pomocí rozšířených událostí

Tento týden vyučujeme IEPTO2 v Dublinu (a pokud Irsko není na vašem seznamu míst, která můžete v tomto životě vidět, musíte to přidat… je to tady fantastické) a dnes jsem dokončil modul Analýza plánu dotazů. Jedna věc, kterou pokrývám, jsou zajímavé věci, které můžete najít v plánu dotazů, například:

  • NoJoinPredicate (2005 a vyšší)
  • ColumnsWithNoStatistics (2005 a vyšší)
  • UnmatchedIndexes (2008 a vyšší)
  • PlanAffectingConvert (2012 a vyšší)

Tyto atributy je dobré hledat, když se při ladění díváte na jeden plán nebo sadu plánů. Pokud ale chcete být trochu proaktivnější, můžete začít těžit keš plánu a hledat je tam. To samozřejmě vyžaduje napsat nějaký XQuery, protože plány jsou XML (podrobnosti o schématu showplanu najdete na:http://schemas.microsoft.com/sqlserver/2004/07/showplan/). Nemám rád XML, i když ne z nedostatku vyzkoušení, a když se jeden z účastníků zeptal, zda byste mohli prostřednictvím Extended Events zachytit dotazy s atributem NoJoinPredicate, pomyslel jsem si:„To je skvělý nápad, budu muset zkontrolovat .“

Jistě, existuje na to událost. Pro všechny čtyři, které jsem uvedl výše, existuje událost:

  • missing_join_preddicate
  • chybějící_statistiky_sloupců
  • unmatched_filtered_indexes
  • plan_afffecting_convert

Pěkný. Jejich nastavení v relaci Extended Events je docela jednoduché. V tomto případě bych doporučil použít cílový soubor event_file, protože pravděpodobně spustíte relaci události a necháte ji chvíli běžet, než se vrátíte a zkontrolujete výstup. Zahrnul jsem několik akcí s nadějí, že tyto události nebudou to spuštěny často, takže zde nepřidáváme příliš mnoho režií. Zahrnul jsem sql_text, i když to není akce, na kterou byste se měli skutečně spolehnout. Jonathan o tom diskutoval dříve, ale sql_text vám pouze poskytuje vstupní vyrovnávací paměť, takže možná nedostanete celý příběh pro dotaz. Z toho důvodu jsem zahrnul také plan_handle. Varování je, že v závislosti na tom, kdy plán jdete hledat, už nemusí být v mezipaměti plánu.

-- Odeberte relaci události, pokud existuje, POKUD EXISTUJE (VYBERTE 1 Z [sys].[server_event_sessions]WHERE [name] ='InterestingPlanEvents')ZAČNĚTE ZRUŠIT RELACI UDÁLOSTI [InterestingPlanEvents] NA SERVERENDGO -- Definujte relaci událostiCREATE EVENT SESSION [InterestingPlanEvents] ]NA UDÁLOSTI SERVERADD sqlserver.missing_column_statistics( ACTION(sqlserver.database_id,sqlserver.plan_handle,sqlserver.sql_text) WHERE ([package0].[equal_boolean]([sqlserver].[))l_system],(0)l_system],(q) database_id]>(4))), PŘIDAT UDÁLOST sqlserver.missing_join_preddicate( ACTION(sqlserver.database_id,sqlserver.plan_handle,sqlserver.sql_text) WHERE ([sqlserver].[is_system]=(0) AND [databázový_server].[databázový_server].[>(4))), PŘIDAT UDÁLOST sqlserver.plan_affecting_convert( ACTION(sqlserver.database_id,sqlserver.plan_handle,sqlserver.sql_text) WHERE ([package0].[equal_boolean]([sqlserver].[is_system],(0)) [sqlserver].[database_id]>(4))),PŘIDAT UDÁLOST sqlserver.unmatched_filtered_indexes( ACTION(sqlserver.plan_handle,sqlserver.sql_text ) WHERE ([balíček0].[equal_boolean]([sqlserver].[je_systém],(0)) AND [sqlserver].[id_databáze]>(4))) PŘIDAT CÍL package0.event_file( SET název_souboru=N'C:\temp\InterestingPlanEvents' /* změňte umístění, je-li to vhodné */)WITH (MAX_MEMORY=4096 KB,EVENT_RETENTION_MODE=ALLOW_SINGLE_EVENT_LOSS,MAX_DISPATCH_LATENCY=5 SEKUND,MAX_EVENT_SIZE=0 KB,_STATITY=OFF --START_JEDNOHO ODDĚLENÍ,_VYP. Zahájit relaci událostiALTER EVENT SESSION [InterestingPlanEvents] NA STAVU SERVERU=START;GO

Jakmile budeme mít relaci události nastavenou a spuštěnou, můžeme tyto události vygenerovat pomocí níže uvedeného ukázkového kódu. Všimněte si, že tento kód předpokládá novou instalaci AdventureWorks2014. Pokud žádný nemáte, možná neuvidíte spuštění události missing_column_statistics, pokud budete dotázáni na sloupec [HireDate] v [HumanResources].[Zaměstnanec].

-- Tyto dotazy předpokládají ČERSTVOU obnovu DATABÁZE AdventureWorks2014ALTER [AdventureWorks2014] VYPNĚTE AUTO_CREATE_STATISTICS;POUŽÍVEJTE [AdventureWorks2014];PŘEJTE VYTVOŘIT INDEX [NCI_SalesOrderHeader] [SurchalesOrderHeader] ZAPNUTO [SalesOrder]ust[SaurchalesOr]ust [CelkemDue], [Datum splatnosti]) KDE [Mezisoučet] > 10000.00;GO /*No join preddicatePOZNÁMKA:Zde vymažeme proceduru, protože událost se spustí POUZE pro *počáteční* kompilaci*/DBCC FREEPROCCACHE; /* Není určeno pro produkční použití */ SELECT [h].[SalesOrderID], [d].[SalesOrderDetailID], [h].[CustomerID]FROM [Sales].[SalesOrderDetail] [d],[Sales].[SalesOrderHeader ] [h]WHERE [d].[ProductID] =897;GO -- Sloupce bez statistik VYBERTE [ID_podniku], [NationalIDNumber], [JobTitle], [HireDate], [ModifiedDate]OD [HumanResources].[Employee]WHERE [HireDate] >='2013-01-01';GO -- Nesrovnatelný indexDECLARE @Total MONEY =10000,00; VYBERTE [Číslo nákupní objednávky], [Číslo zákazníka], [Celkový splatnost], [Datum splatnosti] Z [Prodeje].[SalesOrderHeader] KDE [Mezisoučet] > @Total;GO -- Plán ovlivňující převod SELECT [BusinessEntityID], [NationalIDNumber], [JobTitle], [HireDate], [ModifiedDate]OD [HumanResources].[Zaměstnanec]WHERE [NationalIDNumber] =345106466 NA SERVERSTATE=STOP;PŘEJÍT RELACI UDÁLOSTI DROP [InterestingPlanEvents]NA SERVERU;PŘEJÍT

POZNÁMKA:PO dokončení stahování plánů z mezipaměti můžete spustit příkaz ALTER a povolit možnost automatického vytváření statistik. Pokud tak učiníte v tomto okamžiku, vymaže se mezipaměť plánu a budete muset začít znovu s testováním. (A také počkejte, až budete hotovi, abyste index zrušili.)

ALTER DATABASE [AdventureWorks2014] NASTAVIT AUTO_CREATE_STATISTICS ON;PŘEJÍT DROP INDEX [NCI_SalesOrderHeader] ON [Sales].[SalesOrderHeader];GO

Protože jsem zastavil relaci události, otevřu výstupní soubor v SSMS, abych viděl, co jsme zachytili:

Výstup z rozšířených událostí

Pro náš první dotaz s chybějícím predikátem spojení máme jednu událost, která se zobrazí, a text dotazu vidím v poli sql_text. Co však opravdu chci, je podívat se také na plán, abych mohl vzít plan_handle a zkontrolovat sys.dm_exec_query_plan:

SELECT query_plan FROM sys.dm_exec_query_plan(0x06000700E2200333405DD12C000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 

A otevření v SQL Sentry Plan Explorer:

Chybí predikát připojení

Plán má vizuální indikátor chybějícího predikátu spojení ve vnořené smyčce (červené X), a když na něj najedu kurzorem, zobrazí se varování (a je v XML pro plán). Výborně...Nyní mohu mluvit se svými vývojáři o přepsání tohoto dotazu.

Další událost je pro chybějící statistiku sloupce. Tuto situaci jsem si zcela vynutil vypnutím AUTO_CREATE_STATISTICS pro databázi AdventureWorks2014. Nedoporučuji to žádným způsobem, tvarem ani formou. Tato možnost je ve výchozím nastavení povolena a doporučuji ji vždy ponechat povolenou. Vypnutí je však nejjednodušší způsob, jak tuto událost vygenerovat. Znovu mám dotaz v poli sql_text, ale znovu použiji plan_handle k vytažení plánu:

SELECT query_plan FROM sys.dm_exec_query_plan(0x060007004448323810921C36000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 

Chybí statistika

A máme opět vizuální narážku (žlutý trojúhelník s vykřičníkem), který naznačuje, že s plánem je problém, a opět je to v XML. Odtud bych nejprve zkontroloval, zda je AUTO_CREATE_STATISTICS zakázáno, a pokud ne, začal bych spouštět dotaz v Management Studio, abych zjistil, zda mohu znovu vytvořit varování (a vynutit vytvoření statistiky).

Nyní jsou zbývající události o něco zajímavější.

Všimnete si, že máme tři události unmatched_filtered_indexes. Ještě musím určit proč, ale pracuji na tom a zveřejním v komentářích, pokud/až to vyřeším. Prozatím stačí, že mám událost a v rámci události můžeme také vidět informace o objektu, abych znal dotyčný index:

Na index NCI_SalesOrderHeader odkazuje chybějící událost indexu

A znovu mohu použít plan_handle k nalezení plánu dotazů:

Neodpovídající index

Tentokrát vidím varování v operátoru SELECT, takže vím, že je něco, co musím dále prozkoumat. V tomto případě máte možnosti, jak přimět optimalizátor, aby používal filtrovaný index, když používáte parametry, a doporučuji projít Aaronův příspěvek, kde najdete další informace o používání filtrovaných indexů.

Nakonec máme devět událostí pro plan_afffecting_convert. Co to sakra? Stále na to přicházím, ale použil jsem možnost Sledovat příčinnou souvislost pro svou relaci události (při testování), abych potvrdil, že všechny události jsou součástí stejného úkolu (jsou). Pokud se podíváte na prvek výrazu ve výstupu, uvidíte, že se mírně mění (stejně jako kompilační_čas), a to se objeví, když se podíváte na podrobnosti varování v SQL Sentry’s Plan Explorer (viz druhý snímek obrazovky níže). V rámci výstupu události prvek výrazu dělá řekněte nám, o jaký sloupec se jedná, což je začátek, ale málo informací, takže znovu musíme jít získat plán:

SELECT query_plan FROM sys.dm_exec_query_plan(0x0600070023747010E09E1C360000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 

Plán ovlivňující konverzi

Podrobnosti konverze z plánu

Opět vidíme našeho přítele, žlutý trojúhelník, v operátoru SELECT a v XML najdeme atribut PlanAffectingConvert. Tento atribut byl přidán do schématu showplan SQL Server 2012, takže pokud používáte starší verzi, v plánu to neuvidíte. Vyřešení tohoto varování může vyžadovat trochu více práce – musíte pochopit, kde dochází k nesouladu datových typů a proč, a poté buď začněte upravovat kód nebo schéma… obojí může narazit na odpor. Jonathan má příspěvek, který podrobněji pojednává o implicitní konverzi, což je dobré místo, kde začít, pokud jste s problémy s převodem ještě nepracovali.

Shrnutí

Knihovna událostí Extended Events se neustále rozrůstá a jedna věc, kterou je třeba zvážit při odstraňování problémů na serveru SQL Server, je, zda můžete získat informace, které hledáte, jiným způsobem. Možná proto, že je snazší (určitě preferuji XE před XML!), nebo proto, že je efektivnější nebo poskytuje více podrobností. Ať už proaktivně hledáte problémy s dotazy ve svém prostředí nebo reagujete na problém, který někdo nahlásil, ale máte potíže ho najít, rozšířené události jsou životaschopnou možností, kterou je třeba zvážit, zvláště když jsou do SQL Serveru přidány další nové funkce.


  1. Příklady MySQL REGEXP

  2. Vysvětlení použití jednoduchých uvozovek MySQL, dvojitých uvozovek, zpětných uvozovek

  3. .NET 4:Jak nakonfigurovat soubor EDMX v jiném sestavení ve Web.Config

  4. [Video] Síla indexování v PostgreSQL