sql >> Database >  >> RDS >> Database

Het transactielogboekvet bijsnijden

In veel SQL Server-workloads, met name OLTP, kan het transactielogboek van de database een knelpunt zijn dat bijdraagt ​​aan de tijd die nodig is om een ​​transactie te voltooien. De meeste mensen gaan ervan uit dat het I/O-subsysteem het echte knelpunt is, omdat het de hoeveelheid transactielogboeken die door de werkbelasting wordt gegenereerd, niet kan bijhouden.

Schrijfwachttijd transactielogboek

De latentie van schrijfbewerkingen naar het transactielogboek kan worden gecontroleerd met behulp van de sys.dm_io_virtual_file_stats DMV en gecorreleerd met de WRITELOG wachttijden die op het systeem plaatsvinden. Ik heb in 2011 een demovideo opgenomen van het analyseren van transactielogboek-I/O, dus ik zal dat niet allemaal herhalen in dit bericht. Je kunt de video hier krijgen en de democode hier (geschikt om meteen in productie te gaan).

Als de schrijflatentie hoger is dan je zou verwachten voor je I/O-subsysteem, dan kan het I/O-subsysteem het niet bijhouden, zoals de algemene veronderstelling is. Betekent dit dat het I/O-subsysteem echter moet worden verbeterd? Niet noodzakelijk.

Op veel clientsystemen heb ik ontdekt dat een aanzienlijk deel van de gegenereerde logrecords niet nodig is, en als u het aantal gegenereerde logrecords kunt verminderen, vermindert u de hoeveelheid transactielog die naar schijf wordt geschreven. Dit zou zich moeten vertalen in een vermindering van de schrijflatentie, waardoor de voltooiingstijd van de transactie wordt verkort.

Er zijn twee hoofdoorzaken voor het genereren van externe logrecords:ongebruikte niet-geclusterde indexen en indexen die gefragmenteerd raken.

Ongebruikte niet-geclusterde indexen

Telkens wanneer een record in een tabel wordt ingevoegd, moet een record worden ingevoegd in elke niet-geclusterde index die in de tabel is gedefinieerd (met uitzondering van gefilterde indexen met geschikte filters, die ik vanaf dit punt zal negeren). Dit betekent dat er voor elke tabelinvoeging extra logrecords worden gegenereerd, ten minste één per niet-geclusterde index. Hetzelfde geldt voor het verwijderen van een record in een tabel - de overeenkomende records moeten worden verwijderd uit alle niet-geclusterde indexen. Voor een update van een tabelrecord worden niet-geclusterde indexrecords alleen bijgewerkt als de niet-geclusterde indexsleutelkolom(men) of opgenomen kolom(men) deel uitmaakten van de update.

Deze bewerkingen zijn natuurlijk nodig om elke niet-geclusterde index correct te houden met betrekking tot de tabel, maar als de niet-geclusterde index niet wordt gebruikt door de werkbelasting, zijn de bewerkingen en de logboekrecords die ze produceren onnodige overhead. Bovendien, als deze ongebruikte indexen gefragmenteerd raken (wat ik later in dit bericht zal bespreken), zullen de reguliere indexonderhoudstaken er ook op werken, waardoor nog meer logrecords worden gegenereerd (van de index REBUILD of REORGANIZE operaties) volledig onnodig.

Ongebruikte indexen komen uit verschillende bronnen, zoals iemand die per vergissing een index per tabelkolom aanmaakte, iemand die elke index aanmaakt die wordt voorgesteld door de ontbrekende index-DMV's, of iemand die alle indexen aanmaakt die worden voorgesteld door de Database Tuning Advisor. Het kan ook zijn dat de kenmerken van de werkbelasting zijn veranderd en dat wat vroeger bruikbare indexen waren, niet meer worden gebruikt.

Waar ze ook vandaan komen, ongebruikte indexen moeten worden verwijderd om hun overhead te verminderen. U kunt bepalen welke indexen ongebruikt zijn met behulp van de DMV sys.dm_db_index_usage_stats, en ik raad u aan de berichten van mijn collega's Kimberly L. Tripp (hier) en Joe Sack (hier en hier) te lezen, omdat ze uitleggen hoe de DMV correct moet worden gebruikt.

Indexfragmentatie

De meeste mensen beschouwen indexfragmentatie als een probleem dat van invloed is op query's die grote hoeveelheden gegevens moeten lezen. Hoewel dit een van de problemen is die fragmentatie kan veroorzaken, is fragmentatie ook een probleem vanwege de manier waarop het optreedt.

Fragmentatie wordt veroorzaakt door een bewerking die een paginasplitsing wordt genoemd. De eenvoudigste oorzaak van een paginasplitsing is wanneer een indexrecord op een bepaalde pagina moet worden ingevoegd (vanwege de sleutelwaarde) en de pagina niet voldoende vrije ruimte heeft. In dit scenario vinden de volgende bewerkingen plaats:

  • Er wordt een nieuwe indexpagina toegewezen en opgemaakt
  • Sommige records van de volledige pagina worden naar de nieuwe pagina verplaatst, waardoor er vrije ruimte op de vereiste pagina ontstaat
  • De nieuwe pagina is gekoppeld aan de indexstructuur
  • Het nieuwe record wordt ingevoegd op de gewenste pagina

Al deze bewerkingen genereren logrecords en zoals u zich kunt voorstellen, kan dit aanzienlijk meer zijn dan nodig is om een ​​nieuw record in te voegen op een pagina waarvoor geen paginasplitsing nodig is. In 2009 blogde ik over een analyse van de kosten voor het splitsen van pagina's in termen van het transactielogboek en vond ik enkele gevallen waarin een paginasplitsing meer dan 40 keer meer transactielogboek opleverde dan een gewone invoeging!

De eerste stap bij het verlagen van de extra kosten is het verwijderen van ongebruikte indexen, zoals ik hierboven heb beschreven, zodat ze geen paginasplitsingen genereren. De tweede stap is het identificeren van resterende indexen die gefragmenteerd raken (en dus paginasplitsingen moeten hebben) met behulp van de sys.dm_db_index_physical_stats DMV (of de nieuwe SQL Sentry Fragmentation Manager) en proactief vrije ruimte erin creëren met behulp van een index-vulfactor. Een fillfactor instrueert SQL Server om lege ruimte op indexpagina's te laten wanneer de index wordt gebouwd, opnieuw opgebouwd of gereorganiseerd, zodat er ruimte is om nieuwe records in te voegen zonder dat een pagina hoeft te worden opgesplitst, waardoor de extra gegenereerde logrecords worden verminderd.

Natuurlijk komt niets gratis - de wisselwerking bij het gebruik van vulfactoren is dat u proactief extra ruimte in de indexen indeelt om te voorkomen dat er meer logrecords worden gegenereerd - maar dat is meestal een goede afweging om te maken. Het kiezen van een vulfactor is relatief eenvoudig en daar heb ik hier over geblogd.

Samenvatting

Het verminderen van de schrijflatentie van een transactielogbestand betekent niet altijd dat u naar een sneller I/O-subsysteem moet gaan of dat het bestand moet worden gescheiden in een eigen deel van het I/O-subsysteem. Met een eenvoudige analyse van de indexen in uw database kunt u mogelijk het aantal gegenereerde transactielogboekrecords aanzienlijk verminderen, wat leidt tot een evenredige vermindering van de schrijflatentie.

Er zijn andere, subtielere problemen die de prestaties van transactielogboeken kunnen beïnvloeden, en die zal ik in een volgende post onderzoeken.


  1. Verschil tussen TRIM() en TRIM_ORACLE() in MariaDB

  2. SQL Server-afkapping en 8192-beperking

  3. SQL Server 2016 Enterprise Edition Prestatievoordelen

  4. Slaapstand native query - char (3) kolom