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

Spørgsmål og svar fra vores Parameter Sniffing-webinarserie

De seneste to onsdage har vi været vært for en todelt webinarserie, der behandler problemer med parameterfølsomhed:

  • Lagrede procedurer, parametre, problemer...
    Kimberly L. Tripp og Aaron Bertrand
    24. januar
    Gik du glip af det? Tilmeld dig for at se det nu!

  • Tagling af parametersniffing ved hjælp af SentryOne
    Aaron Bertrand, Kimberly L. Tripp og Andy Mallon
    31. januar
    Gik du glip af det? Se det nu!

Nogle spørgsmål dukkede op under begge webinarer, og jeg tænkte, at jeg ville samle dem og besvare dem her (nogle af svarene kom fra Andy under webinaret).

I et nummer, vi har set for nylig, ser vi, at planer bliver droppet ud af cachen meget hurtigt. Vi udfører ikke noget, du beskriver (DBCC FREEPROCCACHE etc.); kan hukommelsestryk også få dette til at ske?

Ja, hukommelsestryk kan være en faktor (se dette indlæg), og jeg ved, at der er nogle undersøgelser af potentielle problemer med SQL Servers hukommelsesstyring også i denne henseende.

Fra en deltager:"Ikke et spørgsmål, men en kommentar til brugeren, der spørger om de mange gange, hans plancache er tømt. Det havde vi også, og det var faktisk hukommelsestryk. Vi havde max serverhukommelsen forkert konfigureret, dvs. rettet ved hjælp af formlen nævnt her, og så havde vi proceduren fra denne artikel kørende hvert 10. minut (vi har tonsvis af dynamisk SQL, kun brugt én gang)."

Hvad hvis du bruger OR i where-sætningen i stedet for AND , ville problemet fortsætte?

Typisk hvis du bruger OR i denne type mønster vil du få alle rækker hver gang, medmindre hver enkelt parameter er udfyldt med værdier, der filtrerer rækker. Dette ændrer forespørgslens semantik fra "alle disse ting skal være sande" til "enhver af disse ting kan være sande." Alligevel vil planen, der er kompileret for det første sæt parametre, stadig blive cachelagret og bevaret til fremtidige udførelser, uanset om dine klausuler bruger AND eller OR .

Er det 1=1 flag en god tilgang? Det er bedre kun at tilføje de parametre, der er angivet, og derfor undgå den grimme 1=1 ?

1 = 1 ignoreres praktisk talt af SQL Server, men tillader, at alle betingede klausuler tilføjes med AND så du ikke skal behandle den *første* anderledes. Her er alternativet:

SET @IncludedWhereClauseYet bit = 0;
SET @sql = N'SELECT cols FROM dbo.Table';
 
IF @param1 IS NOT NULL
BEGIN
  IF @IncludedWhereClauseYet = 0
  BEGIN
    SET @sql += N' WHERE ';
    SET @IncludedWhereClauseYet = 1;
  END
  ELSE
  BEGIN
    SET @sql += N' AND ';
  END
  SET @sql += N' @param1 = @param1';
END
 
IF @param2 IS NOT NULL
BEGIN
  IF @IncludedWhereClauseYet = 0
  ...
END
...

1=1 giver dig mulighed for at forenkle ved altid at lade dig præfikse enhver klausul med AND . Ovenstående kode bliver:

SET @sql = N'SELECT cols FROM dbo.Table WHERE 1 = 1';
 
IF @param1 IS NOT NULL
BEGIN
  SET @sql += N' AND @param1 = @param1';
END
 
IF @param2 IS NOT NULL
BEGIN
  SET @sql += N' AND @param2 = @param2';
END

Du kan måske bruge en anden begyndelsessætning for at undgå alle betingelsesbetingelserne, såsom WHERE PrimaryKey > 0 eller WHERE PrimaryKey IS NOT NULL , og så kunne hver efterfølgende klausul starte med AND . Men 1 = 1 , mens grimt, er harmløst, og IMHO er ikke mindre grimt end at tilføje en *rigtig* men meningsløs klausul, bortset fra at en *rigtig* klausul kan påvirke planen.

Husk, at når du konstruerer T-SQL-kode med T-SQL, har du to aspekter af "grimt" at tænke på - nogle gange vil du fejlfinde koden ovenfor, og nogle gange vil du fejlfinde forespørgslen, der kommer ud af det. Vær forsigtig med at ofre den ene for den andens skyld.

HVAD?! Jeg har helt savnet det … WITH RECOMPILE . Jeg troede, at det tømte planen, men det lader den være i fred for netop denne henrettelse... det er meget vigtigt at vide!

Bare sørg for, at du også er opmærksom på ulemperne.
Se dette fantastiske indlæg af Paul White.

Er OPTION OPTIMIZE FOR @parametername UNKNOWN ikke længere foretrukket i nyere SQL-versioner?

Jeg tror ikke, det er bedre eller værre i moderne versioner, end da det først blev introduceret i SQL Server 2008. Så vidt jeg ved, opfører den bit sig stadig på samme måde, selv med alle ændringerne i optimizeren og kardinalitetsestimatoren.

Er der nogen belastning på serveren, hvis jeg aktiverer indfangning af procedurestatistik og forespørgselsstatistik i SentryOne?

Indsamlingen af ​​Procedure &Query-statistik skal være slået til som standard. Al dataindsamling er forbundet med en omkostning, men SQL Sentry er ret forsigtig med, hvor mange omkostninger der afholdes af indsamlingen.

Søgningen på RS brugte det ikke som et resterende prædikat, det søgte på noget andet, jeg ikke kunne se.

Tak, jeg vil gense dette eksempel og blogge om demoerne separat, og sørge for at inkludere alle relevante detaljer, som ikke var tydelige alene fra plandiagrammet.

Er det ikke rigtigt at tilføje nogle af de kolonner, der er nødvendige som INCLUDE s gør faktisk ikke indekset mere effektivt, fordi nøgleopslaget ikke vil blive elimineret? Jeg tænker, at procentdelen ikke bør ændre sig, medmindre du faktisk fjerner nøgleopslaget.

Strengt, ja, det er sandt. Den oprindelige forespørgsel var et altafgørende dårligt eksempel ved at bruge SELECT * og et indeks, der mangler et håbløst antal kolonner. Pointen, jeg prøvede at gøre, er, at fanen Indeksanalyse opfordrer dig til både at (a) forbedre forespørgslen og (b) lave indeksdækningen. Resultatet er der for at lokke dig til at gøre det ene eller begge - hvis du ændrer forespørgslen, så du har brug for færre kolonner, kommer indekset også tættere på at dække forespørgslen. Hvis du vil oprette et nyt, separat, dækkende indeks, har du også informationen om, hvilke kolonner der kræves for at dække denne specifikke forespørgsel. Teknisk set har du ret, at tilføje en inkluderingskolonne, men stadig kræve et opslag for 4 andre, vil ikke få denne specifikke forespørgsel til at fungere bedre, og det vil ikke gøre indekset bedre, men det indikerer, at du kommer tættere på. Håbet er, at du ikke stopper ved blot at tilføje en inkluderingskolonne og ignorere resten. Vi ved ikke, hvornår du stopper, så jeg ved ikke, at der er en perfekt løsning – vi ønsker bestemt ikke at afskrække brugere fra at gøre deres indeks bedre egnet til deres forespørgsler.

Hvorfor ser vi forespørgsler, der bruger parameteren fornavn og efternavn opsummeret under en erklæring, der kun bruger en efternavnsparameter?

OPDATERING: Dette er bevidst. Grupperingen under Vis totaler grupperer den samme procedure kaldet med alle de forskellige parameterkombinationer. Så du kan bruge det først til at bestemme, hvilke parametre der har en tendens til at forårsage den dårligste ydeevne, og inden for det, bore ind i, om der er dataskævhed eller ej. En parameter, der fører til en søgning mod en uindekseret kolonne, for eksempel, vil sandsynligvis boble op til toppen ret pålideligt, og du kan se det i kombination med andre parametre, der sendes og også sammenlignes med alle de kald, hvor den parameter var' t bestået.

Når alt det er sagt, vil vi se på at finjustere denne grupperingsadfærd, efterhånden som vi afslutter ændringer, der i øjeblikket er undervejs, til Top SQL-skærmen.

Er der dokumentation for, hvordan man bruger en planvejledning? Jeg har i øjeblikket ingen idé om, hvordan man gør det.

Dette er noget andet, jeg har tænkt mig at blogge om, men Microsoft har nogle emner her i mellemtiden (og tjek alle de relaterede links i sidebjælken).

Skal jeg aktivere noget for at få Query History Chart?

Nej, dette bør være aktiveret på alle moderne versioner af SentryOne-klientapplikationen. Hvis du ikke kan se det, så prøv Tools > Reset Layout; hvis det ikke virker, kontakt [email protected].

Er der tilfælde, hvor man tvinger sidst kendte gode plan ved hjælp af Query Store, når en planregression er fundet en dårlig idé? Vil det have en tendens til at skjule problemer, der bedre kan løses ved at ændre udsagnet, som du har vist?

At tvinge en plan er ofte en sidste udvej slags mulighed, og jeg har en tendens til at reservere den til tilfælde, hvor du virkelig, virkelig, virkelig ikke kan rette udsagnet (eller ændre indekset). At tvinge en plan kan altid føre til forkert adfærd, fordi det stadig er et menneske, der træffer det valg, og du kan træffe det baseret på dårlig information. Regressionen kan skyldes en planændring, men hvis du vurderer det som en regression, fordi kørselstiden var længere, har du så undersøgt andre mulige årsager? Lad os f.eks. sige, at systemet blev genstartet, eller der var en failover, og fik en ny plan, fordi den gamle blev smidt ud, og måske har statistikkerne også ændret sig i mellemtiden, men nu kører forespørgslen længere, ikke fordi planen er værre, men snarere fordi bufferne var tomme. Så ja, jeg vil bestemt ikke foreslå at tvinge en plan på hver regression.

SentryOne fanger ikke altid data eller parametre hele tiden, så jeg har ikke nok information. Hvordan sikrer jeg mig, at SentryOne fanger parametre og eksekveringsplaner hele tiden?

Det kan du virkelig ikke, fordi det hele afhænger af, hvordan dine forespørgsler udføres, hvordan vi fanger dem, og hvor hurtigt de kører. Ofte kører dine forespørgsler ikke længe nok til at blive fanget fuldt ud, og vi må stole på SQL Servers aggregerede forespørgsels-/procedurestatistikvisninger, som ikke indsamler parameteroplysninger. Du kan ændre indsamlingsindstillinger for Top SQL-kilde for at fange mere og med et hyppigere interval, men du skal afbalancere mængden af ​​data, du indsamler, med hvor meget yderligere information, den køber til dig.

Kan jeg forespørge efter oplysningerne, så jeg kan automatisere og generere rapporter?

Vi har ikke noget ud af boksen for dig at gøre dette, men lad mig tage det tilbage til holdet og se, hvilke muligheder vi kan finde på. En ting, jeg legede med til dette webinar, var at opbygge en rådgivende betingelse for at fange den slags regressioner, vi leder efter, men tiden blev en faktor.

Hvordan beslutter vi, hvornår vi skal bruge OPTION (RECOMPILE) , som vi hver dag får forskellige planer for forskellige parametre?

Jeg vil sige start med de forespørgsler, der svinger mest med parameterfølsomhed. Hvis jeg har en forespørgsel, der nogle gange tager 2 sekunder, men nogle gange tager 30, og en anden, der går fra 4 sekunder til 6 sekunder,
vil jeg fokusere på den første.

Hvilken er bedre at bruge, OPTION (RECOMPILE) eller QUERYTRACEON , i tilfælde af parametersniffing.

Jeg foretrækker OPTION (RECOMPILE) af to grunde. For det første er det selvdokumenterende; ingen, der læser koden, vil undre sig over, hvad den gør, men ikke alle, der læser koden, vil huske TF-numre som 4136. For det andet, det kræver ikke forhøjede tilladelser – prøv at bruge QUERYTRACEON som en peon.

Er det muligt at advare eller rapportere om procedurer, der tager længere tid end normalt? Mest interesseret i procedurer med højt antal.

Absolut, du kunne bruge en rådgivende betingelse, men det kan blive lidt kompliceret, fordi du – for procedurer, der endda nogle gange kører under indsamlingstærsklen – skal sammenligne snapshots af procedurestatistikken DMV. Jeg har også tilføjet en påmindelse om at blogge om denne, da det er noget, jeg tidligere har hjulpet kunder med at implementere.

Microsoft gør Automatic Tuning til standard for Azure SQL Database, inklusive automatisk plankorrektion. Virker det som en god idé for dig?

Jeg forbeholder mig dommen, indtil jeg (eller nogle kunder) har leget med det. Det er udfordrende nok for dødelige at beslutte sig for, hvordan man tuner; dødelige at skrive software til at tune for dig virker mindst lige så udfordrende, hvis ikke mere. Da Andy så dette spørgsmål, nævnte han for mig, at det mindede ham om SQL Server 2000 – marketingpitchet dengang var, at det var så selvjusterende, at vi ikke havde brug for DBA'er længere. Den påstand er ikke ældet godt.

Det ville være rart at kunne vælge de to prikker på forespørgselshistorik-diagrammet og sammenligne.

Jeg er enig.
Hold dig opdateret.


  1. Databaseskema, autoincrement

  2. Forhindrer SELECT FOR UPDATE, at andre forbindelser indsættes, når rækken ikke er til stede?

  3. MariaDB LCASE() Forklaret

  4. SQL Server REPLACE() vs TRANSLATE():Hvad er forskellene?