sql >> Databasteknik >  >> RDS >> Database

Knee-Jerk Wait Statistik :PAGELATCH

Under de senaste 18 månaderna har jag fokuserat på knästötsreaktioner för att analysera väntastatistik och andra prestationsjusteringsrelaterade ämnen, och i det här inlägget kommer jag att fortsätta med det och diskutera PAGELATCH_XX väntar. XX i slutet av väntan betyder att det finns flera typer av PAGELATCH vänta, och de vanligaste exemplen är:

  • PAGELATCH_SH – ( SH är) väntar på åtkomst till en datafilsida i minnet så att sidinnehållet kan läsas
  • PAGELATCH_EX eller PAGELATCH_UP – (EX clusive eller UP date) väntar på åtkomst till en datafilsida i minnet så att sidinnehållet kan ändras

När en av dessa väntetyper är den vanligaste på en server, är det knäppas att problemet har att göra med I/O (d.v.s. förväxling med PAGEIOLATCH_XX väntetyp, som jag tog upp i ett inlägg 2014) och någon försöker lägga till mer minne eller justera I/O-undersystemet. Ingen av dessa reaktioner kommer att ha någon effekt alls, eftersom datafilsidorna som är föremål för diskussion redan finns i minnet i buffertpoolen!

I alla fall kan du se om du har problem med PAGELATCH_XX strid med hjälp av sys.dm_os_waiting_tasks skript på min blogg eller med hjälp av ett verktyg som Performance Advisor, som visas (för en annan väntetyp) i det här inlägget.

Så vad är källan till påståendet? Först ska jag förklara bakgrunden bakom dessa väntetyper och sedan diskutera de två vanligaste orsakerna till PAGELATCH_XX påstående.

Bakgrund:Spärrar

Innan jag går in på några av orsakerna till PAGELATCH_XX väntar, jag vill förklara varför de ens finns.

I alla flertrådiga system måste datastrukturer som kan nås och manipuleras av flera trådar skyddas för att förhindra scenarier som:

  • Två trådar som uppdaterar en datastruktur samtidigt, och några av uppdateringarna går förlorade
  • En tråd som uppdaterar en datastruktur samtidigt som en annan tråd läser datastrukturen, så lästråden ser en blandning av gammal och ny data

Detta är grundläggande datavetenskap, och SQL Server är inte annorlunda, så alla datastrukturer inuti SQL Server måste ha flertrådad åtkomstkontroll.

En av mekanismerna som SQL Server använder för att göra detta kallas en spärr, där att hålla spärren i exklusivt läge förhindrar andra trådar från att komma åt datastrukturen, och att hålla spärren i delningsläge förhindrar andra trådar från att ändra datastrukturen. SQL Server använder också spinlocks för vissa datastrukturer och jag diskuterade dessa i det här inlägget redan 2014.

Men varför är en datafilsida i minnet skyddad av en spärr, kanske du undrar? Tja, en datafilsida är bara en datastruktur, om än en sådan, och behöver därför samma åtkomstkontroller som vilken annan datastruktur som helst. Så när en tråd behöver ändra en datafilsida måste den skaffa en exklusiv eller uppdatera spärr på sidan, och om den inte kan och behöver vänta, vänta typ PAGELATCH_EX eller PAGELATCH_UP resultat.

Klassisk tempdb-konflikt

PAGELATCH konflikt i tempdb är vanligtvis på allokeringsbitmappar och uppstår med arbetsbelastningar med många samtidiga anslutningar som skapar och släpper små temporära tabeller (som lagras i tempdb).

När den första raden infogas i en temporär tabell måste två sidor tilldelas (en datasida och en IAM-sida som spårar datasidan). Dessa sidor måste markeras som allokerade på en speciell tilldelningssida som kallas en PFS-sida, och som standard tilldelas de från speciella dataomfattningar som spåras av en annan tilldelningssida som kallas en SGAM-sida (detaljer om dessa finns i mitt gamla blogginlägg här). När den tillfälliga tabellen tas bort måste dessa sidor omallokeras igen, vilket kräver fler ändringar av PFS- och SGAM-sidorna.

Om de temporära tabellerna är små och den kumulativa storleken på alla samtidigt skapade temporära tabeller är mindre än 64 MB, centreras alla dessa allokeringsbitmappsändringar på de allra första PFS- och SGAM-sidorna i tempdb-datafilen (med sid-ID (1:1) respektive (1:3). Uppdatering av en av dessa allokeringssidor kräver att sidan låses, och endast en tråd åt gången kan ändra sidan, så alla andra trådar måste vänta – med väntetyp PAGELATCH_UP .

Från SQL Server 2005 och framåt kan temporära tabeller cachelagras när de släpps, så länge de är mindre än 8 MB stora (och i SQL Server 2014 inte skapas i en lagrad procedur som också har DDL-satser på den temporära tabellen). Detta innebär att nästa tråd som kör samma frågeplan kan ta den temporära tabellen ur cachen och inte behöva ta itu med de initiala allokeringarna. Detta minskar påståendet om allokeringsbitmapparna, men den tillfälliga tabellcachen är inte särskilt stor, så arbetsbelastningar med hundratals samtidiga temporära tabellskapningar/bortfall kommer fortfarande att se massor av konflikter.

Det är trivialt att förhindra påståendet på SGAM-sidorna i tempdb genom att aktivera dokumenterad spårningsflagga 1118 på servern, vilket jag säger borde vara aktiverat på alla servrar över hela världen, och är faktiskt det oföränderliga standardbeteendet i SQL Server 2016.

Att förhindra konflikter på PFS-sidorna i tempdb är lite svårare. Om man antar att de temporära tabellerna behövs för prestanda, är tricket att ha flera datafiler för tempdb så att allokeringarna görs runt om bland filerna, argumentet delas upp på flera PFS-sidor och så den övergripande konflikten går ner. Det finns inget rätt svar på hur många datafiler du ska ha tyvärr. Du kan läsa mer om allmänt accepterad vägledning om detta i KB-artikel 2154845 och i detta blogginlägg.

Infoga hotspot

I användardatabaser är en vanlig orsak till det höga antalet PAGELATCH_EX waits är en insatt hotspot.

Detta kan inträffa när en tabell har ett klusterindex med en int- eller bigint-klusternyckel och en radstorlek som är tillräckligt liten så att många tiotals eller fler tabellrader får plats på en datasida på bladnivån för det klustrade indexet.

För en sådan tabell, om arbetsbelastningen involverar många tiotals eller hundratals samtidiga trådar som infogas i tabellen, kommer många av trådarna att generera rader med identitetsvärden (och därmed klusternycklar) som måste infogas på samma datasida på bladnivå .

Kom nu ihåg att en ändring av en datafilsida i minnet kräver en exklusiv spärr, så var och en av de trådar som försöker infogas på samma sida måste exklusivt förvärva sidans spärr. Medan varje tråd håller den exklusiva spärren, kommer de andra trådarna att vänta på PAGELATCH_EX för den sidan, vilket i huvudsak gör de samtidiga infogningarna till en enormt flaskhalsad synkron process.

Det finns några möjliga korrigeringar för detta problem:

  • Använd en mer slumpmässig nyckel och inse att detta kommer att leda till indexfragmentering, så använd även en indexfyllningsfaktor för att förhindra siddelning
  • Sprid ut insatserna i tabellen med någon form av artificiell uppdelningsmekanism
  • Använd en längre tabellradstorlek (detta är uppenbarligen det minst välsmakande alternativet)

Jag har sett en sådan här infogningspunkt dyka upp när någon försökte ta bort indexfragmenteringsproblem genom att ändra en slumpmässig GUID-klusternyckel till en int- eller bigint-identitetsklusternyckel, men misslyckas med att testa det nya tabellschemat under produktionsbelastningar.

Sammanfattning

Precis som med andra väntetyper, förstå exakt vad PAGELATCH_XX waits mean är nyckeln till att förstå hur man felsöker dem.

När det gäller allmän väntestatistik kan du hitta mer information om hur du använder dem för prestandafelsökning i:

  • Min SQLskills blogginläggsserie, som börjar med Vänta statistik, eller snälla berätta för mig var det gör ont
  • Mina väntetyper och låsklasser-bibliotek här
  • Min Pluralsight onlinekurs SQL Server:Prestandafelsökning med hjälp av väntastatistik
  • SQL Sentry Performance Advisor

Tills nästa gång, lycklig felsökning!


  1. En affärsdatamodell för prenumeration

  2. Hur installerar man Postgis till en Keg-installation av [email protected] med Homebrew?

  3. Hur man löser åtkomst nekad för användare 'root'@'localhost' (med lösenord:Ja) när du ansluter MySQL-databas

  4. Hur gör man:Rengör en mysql InnoDB-lagringsmotor?