sql >> Databasteknik >  >> RDS >> Database

APPEND_ONLY_STORAGE_INSERT_POINT-spärren

Jag fortsätter med min serie artiklar om spärrar, och den här gången ska jag diskutera APPEND_ONLY_STORAGE_INSERT_POINT-spärren och visa hur den kan vara en stor flaskhals för tunga uppdateringsarbetsbelastningar där någon av formerna av ögonblicksbildsisolering används.

Jag rekommenderar starkt att du läser det första inlägget i serien före detta, så att du har all allmän bakgrundskunskap om spärrar.

Vad är APPEND_ONLY_STORAGE_INSERT_POINT-spärren?

För att förklara denna spärr måste jag förklara lite om hur ögonblicksbildsisolering fungerar.

När du aktiverar en av de två formerna av versionshantering använder SQL Server en mekanism som kallas versionshantering för att bevara pre-change versioner av en post i versionsbutiken i tempdb. Detta görs på följande sätt:

  • En post identifieras som just på väg att ändras.
  • Den aktuella posten kopieras till versionslagret.
  • Posten har ändrats.
  • Om posten inte redan hade en 14-byte versionstagg , en läggs till i slutet av posten. Taggen innehåller en tidsstämpel (inte en realtid) och en pekare till den tidigare versionen av posten i versionslagret.
  • Om posten redan hade en versionstagg uppdateras den med den nya tidsstämpeln och versionslagringspekaren.

Den instansomfattande versioneringstidsstämpeln ökas när en ny sats eller batch börjar, eller en ny version av en post skapas, i vilken databas som helst där endera formen av ögonblicksbildsisolering är aktiverad. Denna tidsstämpel används för att se till att en fråga bearbetar rätt version av en post.

Föreställ dig till exempel en databas som hade läs committed ögonblicksbild aktiverad, så varje sats är garanterad att se posterna från den tidpunkt då satsen startade. Tidsstämpeln för versionshantering är inställd för när satsen startade, så alla poster som den stöter på som har en högre tidsstämpel är "fel" version, och därför måste den "rätta" versionen, med en tidsstämpel före satsens tidsstämpel, hämtas från versionsbutik. Mekaniken i denna process är inte relevant för detta inlägg.

Så, hur lagras versionerna fysiskt i versionslagret? Hela posten före ändring, inklusive kolumner utanför rad, kopieras till versionslagret, uppdelad i 8 000-byte-bitar, som kan sträcka sig över två sidor om det behövs (t.ex. 2 000 byte i slutet av en sida och 6 000 byte vid början på nästa). Denna speciallagring består av tilldelningsenheter som endast kan läggas till och används endast för versionslagringsoperationer. Det kallas det eftersom ny data bara kan läggas till omedelbart efter slutet av den senast angivna versionen. En ny allokeringsenhet skapas då och då, och detta gör att vanlig versionsbutiksrensning är mycket effektiv – eftersom en onödig allokeringsenhet helt enkelt kan släppas. Återigen, mekaniken bakom detta ligger utanför ramen för detta inlägg.

Och nu kommer vi till definitionen av spärren:alla trådar som behöver kopiera en förändringspost till versionslagret måste veta var insättningspunkten är i den aktuella allokeringsenheten som endast kan läggas till. Denna information skyddas av APPEND_ONLY_STORAGE_INSERT_POINT-spärren.

Hur blir spärren en flaskhals?

Här är problemet:det finns bara ett acceptabelt läge där APPEND_ONLY_STORAGE_INSERT_POINT-spärren kan erhållas:EX-läge (exklusivt). Och som du vet från att läsa introduktionsinlägget till serien, kan bara en tråd åt gången hålla spärren i EX-läge.

Att samla all denna information:när en eller flera databaser har ögonblicksbildsisolering aktiverad, och det finns en tillräckligt hög samtidig arbetsbelastning av uppdateringar av dessa databaser, kommer det att finnas många versioner som genereras av de olika anslutningarna, och denna spärr kommer att bli en lite av en flaskhals, där flaskhalsens storlek ökar när uppdateringsbelastningen ökar där versionshantering är inblandad.

Visar flaskhalsen

Du kan enkelt återskapa flaskhalsen för dig själv. Jag gjorde så här:

  • Skapat en tabell med ett gäng heltalskolumner som heter cXXX där XXX är ett tal och ett klustrade index på en int identitetskolumn som heter DocID
  • Infogade 100 000 poster, med slumpmässiga värden för alla kolumner
  • Skapat ett skript med en oändlig slinga för att välja ett slumpmässigt DocID i intervallet 1 till 10 000, välj ett slumpmässigt kolumnnamn och öka kolumnvärdet med 1 (och skapa en version)
  • Skapade nio identiska skript, men var och en valde från olika nyckelintervall på 10 000 värden
  • Ställ in DELAYED_DURABILITY på FORCED för att minska väntan på WRITELOG (visserligen skulle du sällan göra detta, men det hjälper till att förvärra flaskhalsen för demoändamål)

Jag körde sedan alla tio skripten samtidigt och mätte Access Methods:Index Searches/sek-räknaren för att spåra hur många uppdateringar som skedde. Jag kunde inte använda Databaser:Batch Requests/sek eftersom varje skript bara hade en batch (den oändliga slingan), och jag ville inte använda Transactions/sec eftersom det kan räkna interna transaktioner såväl som den som omsluter varje uppdatering.

När ögonblicksbildsisolering inte var aktiverad, på min Windows 10-bärbara dator som körde SQL Server 2019, fick jag cirka 80 000 uppdateringar per sekund över de tio anslutningarna. När jag sedan vände inställningen READ_COMMMITED_SNAPSHOT till ON för databasen och körde testet igen, sjönk arbetsbelastningen till cirka 60 000 uppdateringar per sekund (en minskning med 25 % i genomströmningen). Från att titta på väntestatistik var 85 % av alla väntan LATCH_EX, och från att titta på låsstatistik var 100 % för APPEND_ONLY_STORAGE_INSERT_POINT.

Tänk på att jag satte upp scenariot för att visa flaskhalsen när den är som värst. I en verklig miljö med blandad arbetsbelastning är den allmänt accepterade vägledningen för en genomströmningsminskning vid användning av ögonblicksbildsisolering 10–15 %.

Sammanfattning

Ett annat potentiellt område som kan påverkas av denna flaskhals är sekundära läsbara tillgänglighetsgrupper. Om en databasreplik är inställd på att vara läsbar använder alla frågor mot den automatiskt ögonblicksbildsisolering, och all uppspelning av loggposter från den primära kommer att generera versioner. Med en tillräckligt hög uppdateringsbelastning som kommer från den primära och många databaser inställda på att vara läsbara, och med parallell redogörelse som normen för sekundärer för tillgänglighetsgrupp, kan APPEND_ONLY_STORAGE_INSERT_POINT-låset bli en flaskhals på en läsbar sekundär för tillgänglighetsgrupp, vilket kan leda till att sekundärt faller efter det primära. Jag har inte testat detta, men det är exakt samma mekanism som jag har beskrivit ovan, så det verkar troligt. I så fall är det möjligt att inaktivera parallell redo med spårningsflagga 3459, men detta kan leda till sämre total genomströmning på sekundären.

Att lägga scenariet för tillgänglighetsgrupp åt sidan, tyvärr, att inte använda ögonblicksbildsisolering är det enda sättet att helt undvika denna flaskhals, vilket inte är ett genomförbart alternativ om din arbetsbelastning förlitar sig på semantiken som tillhandahålls av ögonblicksbildsisolering, eller om du behöver den för att lindra blockeringsproblem (eftersom ögonblicksbildsisolering innebär att läsfrågor inte får delningslås som blockerar ändringsfrågor).

Redigera:från kommentarerna nedan *kan* du ta bort spärrflaskhalsen genom att använda ADR i SQL Server 2019, men då är prestandan mycket sämre på grund av ADR-overheaden. Scenariot där spärren blir en flaskhals på grund av den höga uppdateringsbelastningen är absolut inte ett giltigt användningsfall för ADR.

  1. SQL - Uppdatera flera poster i en fråga

  2. ORACLE och TRIGGERS (infogade, uppdaterade, raderade)

  3. Hur förhindrar jag att en databastrigger återkommer?

  4. Ansluter till Sage från Java