sql >> Database teknologi >  >> RDS >> Database

Indfang udførelsesplanadvarsler ved hjælp af udvidede hændelser

Vi underviser i IEPTO2 i Dublin i denne uge (og hvis Irland ikke er på din liste over steder at se i dette liv, skal du tilføje det... det er fantastisk her), og i dag afsluttede jeg modulet forespørgselsplananalyse. En ting, jeg dækker, er interessante ting, du kan finde i forespørgselsplanen, for eksempel:

  • NoJoinPredicate (2005 og nyere)
  • ColumnsWithNoStatistics (2005 og nyere)
  • UmatchedIndex (2008 og nyere)
  • PlanAffectingConvert (2012 og nyere)

Disse egenskaber er gode at kigge efter, når du ser på en enkelt plan eller et sæt planer, mens du tuner. Men hvis du vil være lidt mere proaktiv, kan du begynde at mine plancachen og lede efter dem der. Det kræver selvfølgelig at skrive noget XQuery, da planerne er XML (for detaljer om showplan-skemaet, se:http://schemas.microsoft.com/sqlserver/2004/07/showplan/). Jeg elsker ikke XML, dog ikke på grund af mangel på forsøg, og da en af ​​deltagerne spurgte, om du kunne fange forespørgsler, der havde NoJoinPredicate-attributten gennem Extended Events, tænkte jeg, "Sikke en god idé, jeg bliver nødt til at tjekke .”

Selvfølgelig er der en begivenhed for det. Der er en begivenhed for alle fire af dem, jeg har nævnt ovenfor:

  • missing_join_predicate
  • missing_column_statistics
  • unmatched_filtered_indexes
  • plan_påvirker_konverter

Pæn. Det er ret ligetil at konfigurere disse i en udvidet begivenhedssession. I dette tilfælde vil jeg anbefale at bruge event_file-målet, da du sandsynligvis vil starte begivenhedssessionen og lade den køre lidt, før du går tilbage og gennemgår outputtet. Jeg har inkluderet et par handlinger med håbet om, at disse begivenheder ikke affyres at ofte, så vi tilføjer ikke for meget overhead her. Jeg inkluderede sql_text, selvom det ikke er en handling, du virkelig bør stole på. Jonathan har diskuteret dette før, men sql_text giver dig bare inputbufferen, så du får muligvis ikke hele historien til forespørgslen. Af den grund inkluderede jeg også plan_handle. Forbeholdet er, at afhængigt af hvornår du går og leder efter planen, er den muligvis ikke længere i planens cache.

-- Fjern begivenhedssession, hvis den eksisterer HVIS EKSISTERER (VÆLG 1 FRA [sys].[server_event_sessions]WHERE [name] ='InterestingPlanEvents')BEGIN SLIP EVENT SESSION [InterestingPlanEvents] PÅ SERVERENDGO -- Definer begivenhedssessionCREATE [Interesting EVENT SESSIONE ]ON SERVERADD EVENT sqlserver.missing_column_statistics( ACTION(sqlserver.database_id,sqlserver.plan_handle,sqlserver.sql_text) WHERE ([pakke0].[equal_boolean]([sqlserver].[er_system],[sql-server]OG. database_id]>(4))),ADD EVENT sqlserver.missing_join_predicate( ACTION(sqlserver.database_id,sqlserver.plan_handle,sqlserver.sql_text) HVOR ([sqlserver].[is_system]=(0) OG [sqlserver].[database_id]>(4))),ADD EVENT sqlserver.plan_affecting_convert( ACTION(sqlserver.database_id,sqlserver.plan_handle,sqlserver.sql_text) WHERE ([pakke0].[equal_boolean]([sqlserver].[er_system],(0)) OG [sqlserver].[database_id]>(4))),ADD EVENT sqlserver.unmatched_filtered_indexes( ACTION(sqlserver.plan_handle,sqlserver.sql_text ) HVOR ([pakke0].[equal_boolean]([sqlserver].[er_system],(0)) OG [sqlserver].[database_id]>(4)))ADD TARGET package0.event_file( SET filnavn=N'C:\temp\InterestingPlanEvents' /* skift placering, hvis det er relevant */)WITH (MAX_MEMORY=4096 KB,EVENT_RETENTION_MODE=ALLOW_SINGLE_EVENT_LOSS,MAX_DISPATCH_LATENCY=5 SEKUNDER,MAX_EVENT_SIZE=0 KB,MEMORY_PARTITION) Start begivenhedssessionenALTER EVENT SESSION [InterestingPlanEvents] PÅ SERVER STATE=START;GO

Når vi har begivenhedssessionen op at køre, kan vi generere disse begivenheder med eksempelkoden nedenfor. Bemærk, at denne kode forudsætter en ny installation af AdventureWorks2014. Hvis du ikke har en, vil du muligvis ikke se missing_column_statistics-hændelsen udløses, hvis du bliver spurgt til kolonnen [HireDate] i [HumanResources].[Employee].

-- Disse forespørgsler forudsætter en FRISK gendannelse af AdventureWorks2014ALTER DATABASE [AdventureWorks2014] SET AUTO_CREATE_STATISTICS OFF;GO USE [AdventureWorks2014];GO CREATE INDEX [NCI_SalesOrderHeader].PÅ [SalesOrderHeader]. [TotalDue], [DueDate]) WHERE [SubTotal] > 10000.00;GO /*No join-prædikatBEMÆRK:Vi rydder procedure her, fordi begivenheden KUN udløses for den *indledende* kompilering*/DBCC FREEPROCCACHE; /* Ikke til produktionsbrug */ VÆLG [h].[SalesOrderID], [d].[SalesOrderDetailID], [h].[CustomerID]FRA [Salg].[SalesOrderDetail] [d],[Salg].[SalesOrderHeader ] [h]HVOR [d].[ProductID] =897;GO -- Kolonner uden statistikVÆLG [BusinessEntityID], [NationalIDNumber], [JobTitel], [HireDate], [ModifiedDate]FRA [HumanResources].[Medarbejder]WHERE [HireDate] >='2013-01-01';GO -- Umatchet IndexDECLARE @Total MONEY =10000,00; VÆLG [PurchaseOrderNumber], [CustomerID], [TotalDue], [DueDate]FRA [Salg].[SalesOrderHeader]HVOR [SubTotal] > @Total;GO -- Plan, der påvirker ConvertSELECT [BusinessEntityID], [NationalIDNumber], [JobTitle], [HireDate], [ModifiedDate]FRA [HumanResources].[Medarbejder]WHERE [NationalIDNumber] =345106466;GO ALTER EVENT PÅ SERVERSTATE=STOP;GO DROP EVENT SESSION [InterestingPlanEvents]PÅ SERVER;GO

BEMÆRK:EFTER du er færdig med at trække planer fra cachen, kan du køre ALTER-sætningen for at aktivere muligheden for automatisk oprettelse af statistik. Hvis du gør det på dette tidspunkt, ryddes planens cache, og du bliver nødt til at starte forfra med din test. (Og vent også, indtil du er færdig med at droppe indekset.)

ALTER DATABASE [AdventureWorks2014] SET AUTO_CREATE_STATISTICS ON;GO DROP INDEX [NCI_SalesOrderHeader] ON [Sales].[SalesOrderHeader];GO

Da jeg har stoppet begivenhedssessionen, åbner jeg outputfilen i SSMS for at se, hvad vi fangede:

Output fra udvidede begivenheder

For vores første forespørgsel med et manglende join-prædikat har vi en begivenhed, der dukker op, og jeg kan se teksten til forespørgslen i sql_text-feltet. Men det, jeg virkelig ønsker, er også at se på planen, så jeg kan tage plan_handle og tjekke sys.dm_exec_query_plan:

meget

Og åbner det i SQL Sentry Plan Explorer:

Manglende tilmeldingsprædikat

Planen har en visuel indikator for det manglende join-prædikat i den indlejrede løkke (det røde X), og hvis jeg svæver over det, ser jeg advarslen (og det er i XML for planen). Fremragende ... Jeg kan nu gå og tale med mine udviklere om at omskrive denne forespørgsel.

Den næste begivenhed er for en manglende kolonnestatistik. Jeg fremtvang denne situation fuldstændigt ved at slå AUTO_CREATE_STATISTICS fra for AdventureWorks2014-databasen. Jeg anbefaler ikke dette på nogen måde, form eller form. Denne mulighed er aktiveret som standard, og jeg anbefaler altid at lade den være aktiveret. At slå det fra er dog den nemmeste måde at generere denne begivenhed på. Jeg har igen forespørgslen i sql_text-feltet, men jeg bruger plan_handle igen til at trække planen:

VÆLG query_plan FROM sys.dm_exec_query_plan(0x060007004448323810921C360000000000100000000000000000000000000000000000000);
 Manglende statistik 

Og vi har igen et visuelt signal (den gule trekant med udråbstegn) for at indikere, at der er et problem med planen, og igen er det i XML. Herfra vil jeg først kontrollere, om AUTO_CREATE_STATISTICS er deaktiveret, og hvis ikke, vil jeg begynde at køre forespørgslen i Management Studio for at se, om jeg kan genskabe advarslen (og tvinge statistikkerne til at oprette).

Nu er de resterende begivenheder lidt mere interessante.

Du vil bemærke, at vi har tre unmatched_filtered_indexes begivenheder. Jeg har endnu ikke fastslået hvorfor, men jeg arbejder på det og vil skrive i kommentarerne, hvis/når jeg får det ordnet. For nu er det nok, at jeg har begivenheden, og inden for begivenheden kan vi også se objektinformation, så jeg kender det pågældende indeks:

NCI_SalesOrderHeader-indekset refereret af manglende indekshændelse

Og jeg kan igen tage plan_handle for at finde forespørgselsplanen:

Umatchet indeks

Denne gang ser jeg advarslen i SELECT-operatoren, så jeg ved, at der er noget, jeg skal undersøge nærmere. I dette tilfælde har du muligheder for at få optimeringsværktøjet til at bruge det filtrerede indeks, når du bruger parametre, og jeg anbefaler at gå gennem Aarons indlæg for at få flere oplysninger om brug af filtrerede indekser.

Endelig har vi ni begivenheder for plan_affecting_convert. Hvad pokker? Jeg er stadig ved at finde ud af denne, men jeg brugte muligheden Track Causality til min begivenhedssession (når jeg testede) for at bekræfte, at alle begivenheder er en del af den samme opgave (det er de). Hvis du ser på udtrykselementet i outputtet, kan du se, at det ændrer sig lidt (det samme gør compile_time), og dette dukker op, når du ser på detaljerne i advarslen i SQL Sentrys Plan Explorer (se andet skærmbillede nedenfor). Inden for hændelsesoutputtet gør det udtrykselementet fortæl os, hvilken kolonne det drejer sig om, hvilket er en start, men ikke nær nok information, så igen skal vi hente planen:

VÆLG query_plan FROM sys.dm_exec_query_plan(0x0600070023747010E09E1C360000000000100000000000000000000000000000000000000);
 Plan, der påvirker konverter 

Konverteringsdetaljer fra planen

Vi ser igen vores ven, den gule trekant, i SELECT-operatoren, og i XML kan vi finde PlanAffectingConvert-attributten. Denne attribut blev tilføjet i SQL Server 2012 showplan-skemaet, så hvis du kører en tidligere version, vil du ikke se dette i planen. At løse denne advarsel kan kræve lidt mere arbejde - du skal forstå, hvor du har en datatype-uoverensstemmelse og hvorfor, og derefter enten begynde at ændre kode eller skemaet ... begge kan blive mødt med modstand. Jonathan har et indlæg, der diskuterer implicit konvertering mere detaljeret, hvilket er et godt sted at starte, hvis du ikke tidligere har arbejdet med konverteringsproblemer.

Oversigt

Biblioteket med udvidede begivenheder fortsætter med at vokse, og én ting at overveje, når du fejlfinder i SQL Server, er, om du kan få den information, du søger, på en anden måde. Måske fordi det er nemmere (jeg foretrækker helt sikkert XE frem for XML!), eller fordi det er mere effektivt eller giver dig flere detaljer. Uanset om du proaktivt leder efter forespørgselsproblemer i dit miljø eller reagerer på et problem, som nogen har rapporteret, men du har problemer med at finde det, er udvidede begivenheder en levedygtig mulighed at overveje, især da flere nye funktioner føjes til SQL Server.


  1. Dynamisk SQL (oversætter tabelnavn som parameter)

  2. Hvordan kalder man Oracle Stored Procedure i Python?

  3. Hvordan får man ASCII-værdi i Oracle?

  4. Sammenligning af store og små bogstaver i SQL