sql >> Databasteknik >  >> RDS >> Database

Trimma transaktionsloggen fett

I många SQL Server-arbetsbelastningar, särskilt OLTP, kan databasens transaktionslogg vara en flaskhals som ökar den tid det tar att slutföra en transaktion. De flesta antar att I/O-undersystemet är den verkliga flaskhalsen, eftersom det inte kan hålla jämna steg med mängden transaktionslogg som genereras av arbetsbelastningen.

Skrivfördröjning för transaktionslogg

Latensen för skrivoperationer till transaktionsloggen kan övervakas med hjälp av sys.dm_io_virtual_file_stats DMV och korrelerad med WRITELOG väntar som inträffar på systemet. Jag spelade in en demovideo av analys av transaktionslogg-I/O tillbaka 2011 så jag kommer inte att upprepa allt detta i det här inlägget. Du kan få videon här och demokoden här (lämplig för att köras i produktion direkt).

Om skrivfördröjningen är högre än vad du kan förvänta dig för ditt I/O-undersystem kan I/O-undersystemet inte hänga med, vilket är det allmänna antagandet. Betyder det att I/O-undersystemet behöver förbättras? Inte nödvändigtvis.

På många klientsystem har jag funnit att en betydande del av loggposterna som genereras är onödiga, och om du kan minska antalet loggposter som genereras, minskar du mängden transaktionsloggar som skrivs till disken. Detta bör översättas till en minskning av skrivfördröjningen, vilket minskar transaktionens slutförandetid.

Det finns två huvudorsaker till att främmande loggposter genereras:oanvända icke-klustrade index och index som blir fragmenterade.

Oanvända icke-klustrade index

Närhelst en post infogas i en tabell, måste en post infogas i varje icke-klustrat index som definieras i tabellen (med undantag för filtrerade index med lämpliga filter, som jag kommer att ignorera från denna punkt). Detta innebär att extra loggposter genereras, minst en per icke-klustrade index, för varje tabellinfogning. Samma sak gäller för att ta bort en post i en tabell – de matchande posterna måste tas bort från alla icke-klustrade index. För en uppdatering av en tabellpost uppdateras icke-klustrade indexposter endast om de icke-klustrade indexnyckelkolumnerna eller de inkluderade kolumnerna ingick i uppdateringen.

Dessa operationer är naturligtvis nödvändiga för att hålla varje icke-klustrat index korrekt med avseende på tabellen, men om det icke-klustrade indexet inte används av arbetsbelastningen, är operationerna och loggposterna som produceras av dem onödiga overhead. Dessutom, om dessa oanvända index blir fragmenterade (vilket jag kommer att diskutera senare i det här inlägget), kommer de vanliga indexunderhållsuppgifterna också att fungera på dem, vilket genererar ännu fler loggposter (från indexet REBUILD eller REORGANIZE operationer) helt i onödan.

Oanvända index kommer från en mängd olika källor, som att någon av misstag skapar ett index per tabellkolumn, någon skapar varje index som föreslagits av de saknade index-DMV:erna, eller någon skapar alla index som föreslagits av Database Tuning Advisor. Det kan också vara så att arbetsbelastningsegenskaperna har ändrats och att det som tidigare var användbara index inte längre används.

Var de än kom ifrån bör oanvända index tas bort för att minska deras omkostnader. Du kan avgöra vilka index som är oanvända med hjälp av sys.dm_db_index_usage_stats DMV, och jag rekommenderar att du läser inlägg av mina kollegor Kimberly L. Tripp (här) och Joe Sack (här och här), eftersom de förklarar hur du använder DMV korrekt.

Indexfragmentering

De flesta människor tänker på indexfragmentering som ett problem som påverkar frågor som måste läsa stora mängder data. Även om detta är ett av problemen som fragmentering kan orsaka, är fragmentering också ett problem på grund av hur det uppstår.

Fragmentering orsakas av en operation som kallas siddelning. Den enklaste orsaken till en siddelning är när en indexpost måste infogas på en viss sida (på grund av dess nyckelvärde) och sidan inte har tillräckligt med ledigt utrymme. I det här scenariot kommer följande operationer att äga rum:

  • En ny indexsida tilldelas och formateras
  • En del av posterna från hela sidan flyttas till den nya sidan, vilket skapar ledigt utrymme på den önskade sidan
  • Den nya sidan är länkad till indexstrukturen
  • Den nya posten infogas på den obligatoriska sidan

Alla dessa operationer genererar loggposter, och som du kanske föreställer dig kan detta vara betydligt fler än vad som krävs för att infoga en ny post på en sida som inte kräver en siddelning. Redan 2009 bloggade jag en analys av kostnaden för siddelning i termer av transaktionsloggen och hittade några fall där en siddelning genererade över 40 gånger mer transaktionslogg än en vanlig bilaga!

Det första steget för att minska den extra kostnaden är att ta bort oanvända index, som jag beskrev ovan, så att de inte genererar siddelningar. Det andra steget är att identifiera återstående index som håller på att bli fragmenterade (och så måste drabbas av siddelningar) med hjälp av sys.dm_db_index_physical_stats DMV (eller den nya SQL Sentry Fragmentation Manager) och proaktivt skapa ledigt utrymme i dem med hjälp av en indexfillfactor. En fillfactor instruerar SQL Server att lämna tomt utrymme på indexsidor när indexet byggs, byggs om eller omorganiseras så att det finns utrymme för att tillåta nya poster att infogas utan att det krävs en siddelning, vilket minskar antalet extra loggposter som genereras.

Naturligtvis är ingenting gratis – avvägningen när du använder fillfactors är att du proaktivt tillhandahåller extra utrymme i indexen för att förhindra att fler loggposter genereras – men det är vanligtvis en bra avvägning att göra. Att välja fillfactor är relativt enkelt och jag bloggade om det här.

Sammanfattning

Att minska skrivfördröjningen för en transaktionsloggfil innebär inte alltid att man flyttar till ett snabbare I/O-undersystem, eller att filen segregeras i sin egen del av I/O-undersystemet. Med lite enkel analys av indexen i din databas kan du kanske avsevärt minska mängden transaktionsloggposter som genereras, vilket leder till en motsvarande minskning av skrivfördröjningen.

Det finns andra, mer subtila problem som kan påverka transaktionsloggprestanda, och jag kommer att utforska dem i ett framtida inlägg.


  1. PARSE() vs TRY_PARSE() i SQL Server:Vad är skillnaden?

  2. SQL-fel:ORA-01861:literal matchar inte formatsträngen 01861

  3. MySQL kombinera två kolumner och lägg till en ny kolumn

  4. Hur man väljer * men utan kolumnnamn måste vara unika i varje vy