sql >> Databasteknik >  >> RDS >> Database

Oväntad Clustered Index Fragmentation

I en avvikelse från min "knee-jerk performance tuning"-serie, skulle jag vilja diskutera hur indexfragmentering kan smyga sig på dig under vissa omständigheter.

Vad är indexfragmentering?

De flesta människor tänker på "indexfragmentering" som att betyda problemet där indexbladssidorna är ur funktion – indexbladssidan med nästa nyckelvärde är inte den som är fysiskt sammanhängande i datafilen till indexbladssidan som för närvarande undersöks . Detta kallas logisk fragmentering (och vissa människor hänvisar till det som extern fragmentering – en förvirrande term som jag inte gillar).

Logisk fragmentering inträffar när en indexbladsida är full och det krävs utrymme på den, antingen för en infogning eller för att göra en befintlig post längre (från uppdatering av en kolumn med variabel längd). I så fall skapar Storage Engine en ny, tom sida och flyttar 50 % av raderna (vanligtvis, men inte alltid) från helsidan till den nya sidan. Denna operation skapar utrymme på båda sidorna, vilket gör att infogningen eller uppdateringen kan fortsätta, och kallas en siddelning. Det finns intressanta patologiska fall som involverar upprepade siddelningar från en enda operation och siddelningar som kaskader upp indexnivåerna, men de ligger utanför det här inläggets omfattning.

När en siddelning inträffar orsakar det vanligtvis logisk fragmentering eftersom den nya sidan som tilldelas är högst osannolikt att vara fysiskt angränsande till den som delas. När ett index har mycket logisk fragmentering, saktas indexsökningen ner eftersom den fysiska läsningen av de nödvändiga sidorna inte kan göras lika effektivt (med flersidiga "readahead"-läsningar) när bladsidorna inte lagras i ordning i datafilen .

Det är den grundläggande definitionen av indexfragmentering, men det finns en andra typ av indexfragmentering som de flesta människor inte anser:låg sidtäthet (kallar ibland intern fragmentering, igen, en förvirrande term som jag inte gillar).

Siddensitet är ett mått på hur mycket data som lagras på en indexbladsida. När en siddelning inträffar med det vanliga fallet 50/50, lämnas varje bladsida (den delande och den nya) med en sidtäthet på endast 50 %. Ju lägre sidtäthet, desto mer tomt utrymme finns det i indexet och desto mer diskutrymme och buffertpoolminne kan du tänka dig vara bortkastade. Jag bloggade om det här problemet för några år sedan och du kan läsa om det här.

Nu när jag har gett en grundläggande definition av de två typerna av indexfragmentering, kommer jag att referera till dem kollektivt som helt enkelt "fragmentering".

I resten av det här inlägget skulle jag vilja diskutera tre fall där klustrade index kan bli fragmenterade även om du undviker operationer som uppenbarligen skulle orsaka fragmentering (dvs. slumpmässiga infogningar och uppdateringsposter blir längre).

Fragmentering från raderingar

"Hur kan en radering från en klustrad indexbladssida orsaka en siddelning?" du kanske frågar. Det kommer inte att göra det, under normala omständigheter (och jag satt och funderade på det i några minuter för att försäkra mig om att det inte fanns något konstigt patologiskt fall! Men se avsnittet nedan...) Men raderingar kan göra att sidtätheten blir gradvis lägre.

Föreställ dig fallet där det klustrade indexet har ett bigint-identitetsnyckelvärde, så inlägg kommer alltid att gå till höger sida av indexet och kommer aldrig, aldrig att infogas i en tidigare del av indexet (förutom att någon återsöker identitetsvärdet – potentiellt mycket problematiskt!). Föreställ dig nu att arbetsbelastningen tar bort poster från tabellen som inte längre behövs, varefter spökrensningsuppgiften i bakgrunden kommer att återta utrymmet på sidan och det blir ledigt utrymme.

I avsaknad av några slumpmässiga infogningar (omöjligt i vårt scenario om inte någon återställer identiteten eller anger ett nyckelvärde att använda efter att ha aktiverat SET IDENTITY INSERT för tabellen), kommer inga nya poster någonsin att använda utrymmet som frigjordes från de raderade posterna. Detta innebär att den genomsnittliga sidtätheten för de tidigare delarna av det klustrade indexet kommer att minska stadigt, vilket leder till en ökande mängd slösat diskutrymme och buffertpoolminne som jag beskrev tidigare.

Borttagningar kan orsaka fragmentering, så länge du betraktar siddensitet som en del av "fragmentering".

Fragmentering från Snapshot Isolation

SQL Server 2005 introducerade två nya isoleringsnivåer:ögonblicksbildsisolering och läsbetingad ögonblicksbildsisolering. Dessa två har lite olika semantik, men tillåter i princip att frågor kan se en punkt-i-tidsvy av en databas och för lås-kollisionsfria val. Det är en enorm förenkling, men det räcker för mina syften.

För att underlätta dessa isoleringsnivåer implementerade utvecklingsteamet på Microsoft som jag ledde en mekanism som kallas versionshantering. Sättet som versionshantering fungerar är att närhelst en post ändras, kopieras förändringsversionen av posten till versionslagret i tempdb, och den ändrade inspelade får en 14-byte versionstagg tillagd i slutet av den. Taggen innehåller en pekare till den tidigare versionen av posten, plus en tidsstämpel som kan användas för att avgöra vad som är den korrekta versionen av en post för en viss fråga att läsa. Återigen, väldigt förenklat, men det är bara tillägget av 14-byte som vi är intresserade av.

Så närhelst en post ändras när någon av dessa isoleringsnivåer är aktiv, kan den utökas med 14 byte om det inte redan finns en versionstagg för posten. Vad händer om det inte finns tillräckligt med utrymme för de extra 14 byten på indexbladssidan? Det stämmer, en siddelning kommer att inträffa, vilket orsakar fragmentering.

Big deal, kan du tycka, eftersom posten ändras ändå så om den ändrade storlek ändå så skulle en siddelning förmodligen ha inträffat. Nej – den logiken gäller bara om poständringen skulle öka storleken på en kolumn med variabel längd. En versionstagg kommer att läggas till även om en kolumn med fast längd uppdateras!

Det stämmer – när versionshantering pågår kan uppdateringar av kolumner med fast längd göra att en post expanderar, vilket potentiellt kan orsaka siddelning och fragmentering. Vad som är ännu mer intressant är att en borttagning också kommer att lägga till 14-byte-taggen, så en radering i ett klustrat index kan orsaka en siddelning när versionshantering används!

Summan av kardemumman här är att aktivering av endera formen av ögonblicksbildsisolering kan leda till att fragmentering plötsligt börjar inträffa i klustrade index där det tidigare inte fanns någon möjlighet till fragmentering.

Fragmentering från läsbara sekundärer

Det sista fallet jag vill diskutera är att använda läsbara sekundärer, en del av funktionen för tillgänglighetsgrupp som lades till i SQL Server 2012.

När du aktiverar en läsbar sekundär konverteras alla frågor du gör mot den sekundära repliken till att använda ögonblicksbildsisolering under omslagen. Detta förhindrar frågorna från att blockera den konstanta uppspelningen av loggposter från den primära repliken, eftersom återställningskoden får lås allt eftersom.

För att göra detta måste det finnas 14-byte versionstaggar på poster på den sekundära repliken. Det finns ett problem eftersom alla repliker måste vara identiska så att logguppspelningen fungerar. Tja, inte riktigt. Innehållet i versionstaggen är inte relevant eftersom det bara används på den instans som skapade dem. Men den sekundära repliken kan inte lägga till versionstaggar, vilket gör posterna längre, eftersom det skulle ändra den fysiska layouten för poster på en sida och bryta uppspelningen av loggen. Om versioneringstaggarna redan fanns där kunde den använda utrymmet utan att bryta något.

Så det är precis vad som händer. Storage Engine ser till att alla nödvändiga versionstaggar för den sekundära repliken redan finns där, genom att lägga till dem på den primära repliken!

Så snart en läsbar sekundär replika av en databas skapas, gör varje uppdatering av en post i den primära repliken att posten får en tom 14-byte-tagg tillagd, så att 14-byte tas korrekt med i alla loggposter . Taggen används inte för någonting (såvida inte ögonblicksbildsisolering är aktiverad på själva den primära repliken), men det faktum att den skapas gör att posten expanderar, och om sidan redan är full då...

Ja, aktivering av en läsbar sekundär ger samma effekt på den primära repliken som om du aktiverade ögonblicksbildsisolering på den – fragmentering.

Sammanfattning

Tro inte att eftersom du undviker att använda GUID som klusternycklar och undviker att uppdatera kolumner med variabel längd i dina tabeller så kommer dina klustrade index att vara immuna mot fragmentering. Som jag har beskrivit ovan finns det andra arbetsbelastningar och miljöfaktorer som kan orsaka fragmenteringsproblem i dina klustrade index som du måste vara medveten om.

Tänk nu inte på knä och tänk att du inte ska ta bort poster, inte använda ögonblicksbildsisolering och inte använda läsbara sekundärer. Du måste bara vara medveten om att de alla kan orsaka fragmentering och veta hur man upptäcker, tar bort och mildrar det.

SQL Sentry har ett coolt verktyg, Fragmentation Manager, som du kan använda som ett tillägg till Performance Advisor för att ta reda på var fragmenteringsproblemen finns och sedan åtgärda dem. Du kan bli förvånad över fragmenteringen du hittar när du kollar! Som ett snabbt exempel kan jag här visuellt se – ner till den individuella partitionsnivån – hur mycket fragmentering som finns, hur snabbt det blev på det sättet, eventuella mönster som finns och den faktiska inverkan det har på slösat minne i systemet:

SQL Sentry Fragmentation Manager-data (klicka för att förstora)

I mitt nästa inlägg kommer jag att diskutera mer om fragmentering och hur man kan mildra den för att göra den mindre problematisk.


  1. Topp 9 databashanteringssystem för Joomlas mallar

  2. Hur byter man namn på ett kolumnnamn i SQL?

  3. SQL Server ALL Operatör förklaras

  4. Hur man konverterar versaler till gemener i SQL Server – LOWER()