De senaste två onsdagarna har vi hållit en tvådelad webbseminariumserie som behandlar problem med parameterkänslighet:
- Lagrade procedurer, parametrar, problem...
Kimberly L. Tripp och Aaron Bertrand
24 januari
Har du missat det? Registrera dig för att se den nu! - Tackla parametersniffning med SentryOne
Aaron Bertrand, Kimberly L. Tripp och Andy Mallon
31 januari
Har du missat det? Se den nu!
Några frågor dök upp under båda webbinarierna, och jag tänkte att jag skulle sammanställa dem och svara på dem här (en del av svaren kom från Andy under webbinariet).
I ett nummer som vi har sett nyligen ser vi att planer försvinner ur cachen väldigt snabbt. Vi utför inget du beskriver (
DBCC FREEPROCCACHE
etc.); kan minnestryck också orsaka att detta händer?
Ja, minnestryck kan vara en faktor (se det här inlägget), och jag vet att det finns några undersökningar av potentiella problem med SQL Servers minneshantering även i detta avseende.
Från en deltagare:"Inte en fråga, utan en kommentar till användaren som frågade om de många gånger hans plancache töms. Vi hade det också och det var faktiskt minnestryck. Vi hade maxserverminnet felaktigt konfigurerat, dvs. fixade med formeln som nämns här, och sedan körde vi proceduren från den här artikeln var tionde minut (vi har massor av dynamisk SQL, använd bara en gång)."
Vad händer om du använder
OR
i where-satsen istället förAND
, skulle problemet kvarstå?
Vanligtvis om du använder
OR
i den här typen av mönster får du alla rader varje gång, såvida inte varje enskild parameter är fylld med värden som filtrerar rader. Detta ändrar semantiken för frågan från "alla dessa saker måste vara sanna" till "vilken som helst av dessa saker kan vara sann." Planen som kompileras för den första uppsättningen parametrar kommer fortfarande att cachelagras och bevaras för framtida körningar, oavsett om dina satser använderAND
ellerOR
.
Är det
1=1
flagga ett bra tillvägagångssätt? Det är bättre att bara lägga till parametrarna som tillhandahålls och därför undvika den fula1=1
?
1 = 1
ignoreras praktiskt taget av SQL Server, men tillåter alla villkorliga satser att läggas till medAND
så att du inte behöver behandla den *första* annorlunda. Här är 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
låter dig förenkla genom att alltid låta dig prefixa en sats medAND
. Ovanstående kod blir: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'; ENDDu kan kanske använda en annan initialsats för att undvika alla villkor, som
WHERE PrimaryKey > 0
ellerWHERE PrimaryKey IS NOT NULL
, och sedan kan varje efterföljande sats börja medAND
. Men1 = 1
, även om det är fult, är det ofarligt, och IMHO är inte mindre fult än att lägga till en *riktig* men meningslös klausul, förutom att en *riktig* klausul kan påverka planen.Kom ihåg att när du konstruerar T-SQL-kod med T-SQL har du två aspekter av "ful" att tänka på – ibland kommer du att felsöka koden ovan, och ibland kommer du att felsöka frågan som kommer ur Det. Var försiktig med att offra det ena för det andras skull.
VAD?! Jag har helt missat det …
WITH RECOMPILE
. Jag trodde att det tömde planen, men det lämnar den ifred för just den här avrättningen... det är väldigt viktigt att veta!
Se bara till att du också är medveten om nackdelarna.
Se detta fantastiska inlägg av Paul White.
Är
OPTION OPTIMIZE FOR @parametername UNKNOWN
inte längre att föredra i nyare SQL-versioner?
Jag tror inte att det är bättre eller sämre i moderna versioner än när det först introducerades i SQL Server 2008. Så vitt jag vet, även med alla förändringar av optimeraren och kardinalitetskalkylatorn, fungerar den biten fortfarande på samma sätt.
Finns det någon belastning på servern om jag aktiverar insamling av procedurstatistik och frågestatistik i SentryOne?
Procedur- och frågestatistiksamlingen ska vara aktiverad som standard. All datainsamling kommer med en kostnad, men SQL Sentry är ganska försiktig med hur mycket kostnad som uppstår för insamlingen.
Sökningen på RS använde den inte som ett restpredikat, den sökte på något annat jag inte kunde se.
Tack, jag ska återkomma till det exemplet och blogga om demos separat, och se till att inkludera alla relevanta detaljer som inte var uppenbara bara från plandiagrammet.
Är det inte sant att lägga till några av kolumnerna som behövs som
INCLUDE
s gör faktiskt inte indexet mer effektivt eftersom nyckelsökningen inte kommer att elimineras? Jag tror att procentsatsen inte bör ändras om du inte faktiskt tar bort nyckelsökningen.
Strikt, ja, det är sant. Den ursprungliga frågan var ett mycket dåligt exempel med
SELECT *
och ett index som saknar ett hopplöst antal kolumner. Poängen jag försökte göra är att fliken Indexanalys uppmuntrar dig att både (a) förbättra frågan och (b) göra indextäcket. Poängen är till för att locka dig att göra endera eller båda – om du ändrar frågan så att du behöver färre kolumner kommer indexet närmare att täcka frågan också. Om du ska skapa ett nytt, separat, täckande index, har du också information om vilka kolumner som krävs för att täcka denna specifika fråga. Tekniskt sett har du rätt, att lägga till en inkluderingskolumn men ändå kräva en sökning för fyra andra kommer inte att få den här specifika frågan att prestera bättre, och kommer inte att göra indexet bättre, men det indikerar att du kommer närmare. Förhoppningen är att du inte slutar med att bara lägga till en inkluderingskolumn och ignorerar resten. Vi vet inte när du ska sluta, så jag vet inte att det finns en perfekt lösning – vi vill absolut inte avskräcka användare från att göra sina index bättre lämpade för deras frågor.
Varför ser vi frågor som använder förnamnsparametern och efternamnsparametern sammanfattade under ett uttalande som endast använder en efternamnsparameter?
UPPDATERING: Detta är avsiktligt. Grupperingen under Visa totaler grupperar samma procedur som anropas med alla olika parameterkombinationer. Så du kan använda den först för att avgöra vilka parametrar som tenderar att ge den sämsta prestandan, sedan inom det, fördjupa dig i om det finns dataskev eller inte. En parameter som leder till en sökning mot en oindexerad kolumn, till exempel, kommer förmodligen att bubbla upp till toppen ganska tillförlitligt, och du kan se det i kombination med andra parametrar som skickas och även jämförs med alla anrop där den parametern var' t godkänd.
Med allt detta sagt kommer vi att försöka finjustera detta grupperingsbeteende när vi avslutar ändringar som för närvarande pågår för den översta SQL-skärmen.
Finns det någon dokumentation om hur man använder en planguide? Jag har för närvarande ingen aning om hur man gör det.
Det här är något annat jag har tänkt blogga om, men Microsoft har några ämnen här under tiden (och kolla in alla relaterade länkar i sidofältet).
Behöver jag aktivera något för att få frågehistorikdiagram?
Nej, detta bör vara aktiverat på alla moderna versioner av SentryOne-klientapplikationen. Om du inte ser det, prova
Tools > Reset Layout
; om det inte fungerar, kontakta [email protected].
Finns det fall då man tvingar fram senast kända bra plan med hjälp av Query Store när en planregression upptäcks som en dålig idé? Kommer det att tendera att dölja problem som åtgärdas bättre genom att ändra uttalandet som du har visat?
Att tvinga fram en plan är ofta en sista utväg av alternativ, och jag tenderar att reservera det för fall där du verkligen, verkligen, verkligen inte kan fixa uttalandet (eller ändra indexet). Att tvinga fram en plan kan alltid leda till fel beteende, eftersom det fortfarande är en människa som gör det valet, och du kan göra det baserat på dålig information. Regressionen kan bero på en planändring, men om du bedömer det som en regression eftersom körtiden var längre, har du undersökt andra möjliga orsaker? Låt oss till exempel säga att systemet startades om eller att det var en failover och fick en ny plan för att den gamla vräktes, och kanske statistiken också har ändrats under tiden, men nu körs frågan längre inte för att planen är sämre men snarare för att buffertarna var tomma. Så ja, jag skulle verkligen inte föreslå att man tvingar fram en plan för varje regression.
SentryOne fångar inte alltid data eller parametrar hela tiden, så jag har inte tillräckligt med information. Hur ser jag till att SentryOne fångar parametrar och körplaner hela tiden?
Du kan verkligen inte eftersom allt beror på hur dina frågor utförs, hur vi fångar dem och hur snabbt de körs. Ofta kör dina frågor inte tillräckligt länge för att fångas upp helt, och vi måste lita på SQL Servers aggregerade fråge-/procedurstatistikvyer, som inte samlar in parameterinformation. Du kan ändra insamlingsinställningarna för Top SQL Source för att fånga mer och med ett tätare intervall, men du måste balansera mängden data du samlar in med hur mycket ytterligare information den köper till dig.
Kan jag fråga efter informationen så att jag kan automatisera och generera rapporter?
Vi har inget för dig att göra det här, men låt mig ta det tillbaka till laget och se vilken typ av alternativ vi kan komma på. En sak jag lekte med för detta webbseminarium var att skapa ett rådgivande villkor för att fånga de typer av regressioner vi letar efter, men tiden blev en faktor.
Hur bestämmer vi när vi ska använda
OPTION (RECOMPILE)
, som varje dag får vi olika planer för olika parametrar?
Jag skulle säga börja med de frågor som fluktuerar mest med parameterkänslighet. Om jag har en fråga som ibland tar 2 sekunder men ibland tar 30, och en annan som sträcker sig från 4 sekunder till 6 sekunder,
ska jag fokusera på den första.
Vilken är bättre att använda,
OPTION (RECOMPILE)
ellerQUERYTRACEON
, vid parametersniffning.
Jag föredrar
OPTION (RECOMPILE)
av två skäl. En, det är självdokumenterande; ingen som läser koden kommer att undra vad den gör, men inte alla som läser koden kommer att ha memorerade TF-nummer som 4136. Två, det kräver inga förhöjda behörigheter – försök användaQUERYTRACEON
som en peon.
Är det möjligt att larma eller rapportera om procedurer som tar längre tid än vanligt? Mest intresserad av högtalsprocedurer.
Absolut, du kan använda ett rådgivande villkor, men det kan bli lite komplicerat eftersom – för procedurer som till och med ibland går under insamlingströskeln – skulle du behöva jämföra ögonblicksbilder av procedurstatistiken DMV. Jag har lagt till en påminnelse om att blogga om den här också, eftersom det är något jag har hjälpt kunder att implementera tidigare.
Microsoft gör automatisk justering till standard för Azure SQL Database, inklusive automatisk plankorrigering. Verkar det som en bra idé för dig?
Jag förbehåller mig bedömningen tills jag (eller några kunder) har lekt med det. Att bestämma sig för hur man stämmer är tillräckligt utmanande för dödliga; dödliga att skriva mjukvara för att stämma åt dig verkar minst lika utmanande, om inte mer så. När Andy såg den här frågan nämnde han för mig att den påminde honom om SQL Server 2000 – marknadsföringspitchen då var att den var så självjusterande att vi inte skulle behöva DBA längre. Det påståendet har inte åldrats väl.
Att kunna välja de två prickarna på frågehistorikdiagrammet och jämföra skulle vara trevligt.
Jag håller med.
Håll utkik.