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

SQL Server Internals:Plan Caching Pt. II – Genkompilering af planer

Dette er en del af en SQL Server Internals Plan Caching-serie. Sørg for at læse Kalens første indlæg om dette emne.

SQL Server har eksisteret i over 30 år, og jeg har arbejdet med SQL Server i næsten lige så lang tid. Jeg har set en masse ændringer gennem årene (og årtier!) og versioner af dette utrolige produkt. I disse indlæg vil jeg dele med dig, hvordan jeg ser på nogle af funktionerne eller aspekterne af SQL Server, nogle gange sammen med en smule historisk perspektiv

I min tidligere artikel , talte jeg om SQL-serverdiagnostik, inklusive de forskellige muligheder, som SQL Server har for at genbruge en forespørgselsplan. Vi så på tre typer forespørgselsplaner:adhoc, forberedt og procedure. Jeg afsluttede diskussionen med et kig på en uhensigtsmæssig genbrug af en plan, som kan ske, når SQL Server anvender parametersniffing i de forkerte situationer. Hvis en plan er baseret på en startværdi, der får optimeringsværktøjet til at generere en plan, der passer til den værdi, og den samme plan bruges til en anden værdi, er planen muligvis ikke længere optimal.

Så hvad kan vi gøre, når parametersniffing er et problem? Vi kan tvinge SQL Server til at komme med en ny plan. Normalt kalder vi handlingen med at komme med en ny plan for 'genkompilering', men det burde nok hedde 'genoptimering'. De fleste bruger dog udtrykket 'rekompilere', så det er det, jeg vil bruge her.

Hvis uhensigtsmæssig brug af parametersniffing er et problem, er en simpel løsning bare at fortælle SQL Server om at komme med en ny plan. For individuelle udsagn, som f.eks. med FORBEREDTE planer, der er blevet autoparameteriseret, kan vi tilføje RECOMPILE-tipset til en forespørgsel. Ved at bruge FORCED-parametriseret (omtalt i forrige artikel), vil denne forespørgsel blive parameteriseret.

SELECT * FROM dbo.newsales 
WHERE SalesOrderID < @num;

Hvis vi vil sikre os, at vi får en ny plan, hver gang vi kører denne forespørgsel, med potentielt vidt forskellige værdier for @num, kan vi tilføje RECOMPILE hint som vist:

SELECT * FROM dbo.newsales
  WHERE SalesOrderID < @num
OPTION (RECOMPILE);

For lagrede procedurer har vi tre muligheder. For det første kan vi konstatere, om genkompilering rent faktisk vil hjælpe på ydeevnen ved at udføre proceduren med RECOMPILE-indstillingen:

EXEC get_sales_range 66666 WITH RECOMPILE;

Denne mulighed vil forårsage, at en ny plan genereres kun for denne ene udførelse. Det vil ikke blive gemt og vil bestemt ikke blive genbrugt. Usecount-værdien vist i sp_cacheobjects (beskrevet i det forrige indlæg) for proceduren vil ikke stige, da den oprindelige plan ikke bliver genbrugt.

For det andet, hvis vi finder ud af, at det hjælper at udføre MED RECOMPILE, kunne vi overveje at genskabe proceduren med RECOMPILE-indstillingen, i hvilket tilfælde den aldrig genbruger planen, og proceduren vil slet ikke dukke op i planens cache.

DROP PROC IF EXISTS get_sales_range;GO
CREATE PROC get_sales_range
   @num int
WITH RECOMPILE
AS
    SELECT * FROM dbo.newsales
    WHERE SalesOrderID < @num;
GO

For min simple lille procedure kan det være fornuftigt at bruge MED REKOMPILERING for hele proceduren. Men hvis proceduren er mere kompleks, giver det måske ikke mening at omkompilere hele proceduren, fordi én udsagn giver problemer. Så den tredje mulighed er at bruge RECOMPILE hint til en erklæring i proceduren, så det ser sådan ud:

DROP PROC IF EXISTS get_sales_range;
GO
CREATE PROC get_sales_range
   @num int
AS
    SELECT * FROM dbo.newsales
    WHERE SalesOrderID < @num
    OPTION (RECOMPILE);
GO

Brug af en af ​​disse RECOMPILE-muligheder kan tvinge SQL Server til at komme med en ny plan efter din anmodning. Nu vil vi se på, hvornår din SQL Server-diagnostik kommer med en ny plan, når du ikke anmoder om den, dvs. hvornår opstår automatisk genkompilering af en eksisterende plan?


Automatisk genkompilering af en plan forekommer i to typer situationer:

  • For det første, hvis optimeringsværktøjet bestemmer, at den eksisterende plan ikke længere er korrekt, normalt på grund af en ændring i objektdefinitionerne, skal den komme med en ny plan. For eksempel, hvis du har en plan for en forespørgsel, der vælger fra TabelA, og du derefter slipper flere kolonner eller ændrer datatyper for kolonner i TabelA, vil SQL Server omkompilere forespørgslen for at komme med en plan, der afspejler DDL-ændringerne.
  • Den anden situation, hvor automatisk rekompilering opstår, er når SQL Server bestemmer, at planen muligvis ikke længere er optimal på grund af en ændring i statistik. I de fleste tilfælde, hvis statistik på nogen af ​​kolonnerne eller indekserne er blevet opdateret siden sidste gang, planen blev kompileret, vil den blive genkompileret. Men dette leder til et andet spørgsmål. Hvornår er statistikken opdateret? Statistik kan opdateres automatisk, når nok rækker i de relevante kolonner er ændret. Hvor mange er nok? Det taler vi om lige om lidt.

Som standard opdaterer SQL Server statistikken automatisk på grund af en databaseindstilling, der er TIL som standard. Men hvis du er databaseejer (eller en SQL 'sa', som optræder som ejer i hver database), kan du ændre mulighederne. En af mulighederne hedder AUTO_UPDATE_STATISTICS og en anden hedder AUTO_UPDATE_STATISTICS_ASYNC. Indstillingen AUTO_UPDATE_STATISTICS er TIL i tempdb-databasen, så hver ny database arver denne mulighed. Når denne indstilling er TIL, og forespørgselsudførelsesmotoren registrerer ændringer til et tilstrækkeligt antal rækker, mens en forespørgsel behandles, vil udførelsen afbrydes, mens statistikkerne opdateres, og forespørgslen bliver derefter kompileret igen. Den anden mulighed, AUTO_UPDATE_STATISTICS_ASYNC, kan potentielt have mindre effekt på udførelsestiden for forespørgsler, fordi eksekveringen ikke stopper, på bekostning af at bruge en mulig suboptimal plan. Med den anden mulighed, hvis udførelsesmotoren opdager et behov for at opdatere statistik, affyres en baggrundstråd for at udføre opdateringen, og hovedtråden fortsætter med at udføre forespørgslen med den originale statistik og den oprindelige plan. Den næste forespørgsel, der får adgang til de berørte tabeller og ser de opdaterede statistikker, vil kompilere forespørgslen igen, men den stopper ikke og opdaterer statistikken midt i udførelsen.

Der er et par flere situationer samt nogle forespørgselstip, der styrer, om planer genkompileres eller ej, så jeg vil vise dig et flowchart, jeg deler et flowchart med dig, som jeg har oprettet til mine træningsklasser på SQL Server internals.

Pilen er der, hvor SQL Server begynder at behandle din batch. Den tjekker først, om der allerede er en plan for din batch i cachen, og hvis svaret er NEJ, følger du pilen til højre og kompilerer en plan. Planen lægges i cache, og så starter SQL Server igen. Ja, planen skulle være i cachen denne gang, så så følger den pilen nedad og spørger, om der er brugt et tip kaldet KEEP PLAN. Hvis JA, begynder SQL Server at eksekvere planen med det samme og foretager ikke yderligere kontroller.

Det næste spørgsmål er, om der er foretaget DDL-ændringer. Hvis nej, spørger den om flere andre situationer, som jeg ikke vil være i stand til at tale om i denne artikel. Faktisk vil jeg virkelig ikke gå igennem alle muligheder her. Jeg overlader det til dig. Men hvis du har spørgsmål eller forvirring, er du velkommen til at stille dem i kommentarfeltet her, eller tweet mig på @sqlqueen. Jeg vil påpege spørgsmålet yderst til højre:Er AUTO_STATS_ASYNC TIL? Her kan du se, at hvis svaret er JA, er der to handlinger. Den ene gren begynder bare at udføre med den eksisterende plan, og den anden er baggrundstråden, der opdaterer statistikken, men derefter ikke gør andet. Den næste forespørgsel vil støde på beslutningsboksen i midten "Er nye statistikker tilgængelige" og skulle svare JA, så forespørgslen bliver kompileret igen.

Den eneste anden ting, jeg vil tale om, er spørgsmålet "Er nogen statistik forældet?" Dette betyder dybest set, at statistikkerne er forældede, fordi der er foretaget for mange ændringer. Så nu kan vi tale om, hvor mange der er for mange.

Selvom der er forskellige værdier, der bruges til meget små tabeller, for enhver tabel med mere end 500 rækker i den, før SQL Server 2016, ville statistik blive betragtet som "forældet", når antallet af ændringer i kolonnen, som statistikkerne var baseret på, oversteg 20 % af antallet af rækker i tabellen. Så for en tabel med 1000 rækker kan dette betyde 200 indsættelser, 200 opdateringer eller 200 sletninger. Det kan være 200 rækkeændringer eller 5 rækker opdateret 40 gange hver. SQL Server giver os endda en funktion, der rapporterer, hvor mange ændringer der er foretaget. Du skal slå stats_id-nummeret op for den statistik, du er interesseret i, hvilket ville være index_id, hvis statistikken tilhører et indeks. Stats_id'et kan findes i visningen kaldet sys.stats. I min nyhedstabel bruger jeg denne forespørgsel til at finde ud af, at stats_id for indekset i kolonnen SubTotal er 3.

SELECT name, stats_id FROM sys.stats
WHERE object_id = object_id('newsales');

Så kan jeg bruge den værdi til at se på antallet af ændringer. Lad mig først opdatere nogle rækker:

UPDATE newsales
SET SubTotal = SubTotal * 0.9
WHERE SalesOrderID < 45200
(1541 rækker påvirket)

SELECT * FROM sys.dm_db_stats_properties(object_id('newsales'), 3);  

Faktisk er 20% et STORT tal. Og for mange tabeller kan forespørgsler drage fordel af opdaterede statistikker med langt færre end 20 % af rækkerne opdateret. Fra 2008R2 SP1 inkluderede SQL Server et Traceflag, du kunne bruge til at ændre antallet af rækker til at være en glidende skala, som vist i følgende graf:

Fra og med SQL Server 2016 bruges denne nye algoritme med den glidende skala som standard, så længe du er i kompatibilitetsniveau 130 eller højere.

De fleste automatiske genkompileringer af forespørgselsplaner skyldes ændringer i statistik. Men som jeg nævnte ovenfor, er det ikke den eneste grund til en omkompilering. Men da det er det mest almindelige, kan det være meget nyttigt at være opmærksom på, hvornår og hvordan statistikker opdateres og sørge for, at statistikkerne på dine kritiske tabeller opdateres ofte nok til at sikre, at du får de bedste planer!

Analyser ydeevnedata automatisk for at udføre SQL-serverdiagnostik for at løse problemer hurtigt og identificere servere, hvor ydeevneforringelsen stammer fra. Kom godt i gang med at bruge Spotlight Cloud i dag:


  1. AUTONOMOUS_TRANSACTION

  2. MySQL - længde() vs char_length()

  3. Sådan fungerer funktionen TRANSLATE() i SQL Server (T-SQL)

  4. Sådan opdeles en streng i PostgreSQL