sql >> Database >  >> RDS >> Database

Knee-Jerk Performance Tuning:onjuist gebruik van tijdelijke tabellen

In dit vervolg op mijn serie "knie-jerk performance tuning" wil ik vier veelvoorkomende problemen bespreken die ik zie bij het gebruik van tijdelijke tabellen. Elk van deze problemen kan een werkdruk verlammen, dus het is de moeite waard om ze te kennen en te zoeken in uw omgeving.

Probleem 1:Tijdelijke tabellen gebruiken waar ze niet nodig zijn

https://www.flickr. com/photos/tea_time/3890677277/

Tijdelijke tabellen kunnen op verschillende manieren worden gebruikt (waarschijnlijk is de meest gebruikelijke het opslaan van een tussentijdse resultatenset voor later gebruik), maar u moet niet vergeten dat wanneer u een tijdelijke tabel in een query invoert, u de gegevensstroom door de query-processor.

Beschouw de populatie van een tijdelijke tabel als een harde stop, want er is een query (laten we het de producer noemen) om de tussenliggende resultatenset te produceren, die vervolgens wordt opgeslagen in de tijdelijke tabel in tempdb, en dan de volgende query (laten we de consument) de gegevens uit de tijdelijke tabel opnieuw moet lezen.

Ik heb vaak geconstateerd dat sommige delen van een werkbelasting eigenlijk beter presteren wanneer de tijdelijke tabel volledig is verwijderd, zodat de gegevens van het producentgedeelte van de query naar het consumentengedeelte van de query stromen zonder dat ze in tempdb hoeven te worden bewaard, en de Query Optimizer kan een meer optimaal algemeen plan produceren.

Je zou nu kunnen denken, "dus waarom zou iemand een tijdelijke tabel gebruiken als het de zaken langzamer maakt?" - en terecht! In dat soort gevallen heb ik gemerkt dat het gebruik van een tijdelijke tabel is geïnstitutionaliseerd in het ontwikkelteam; iemand ontdekte dat het gebruik van een tijdelijke tafel vele jaren geleden de prestaties verbeterde, dus tijdelijke tabellen werden de standaard ontwerpkeuze.

Dit kan moeilijk zijn om te veranderen, vooral als je een senior ontwikkelaar of manager hebt die ervan overtuigd is dat tijdelijke tabellen altijd moeten worden gebruikt. Het eenvoudigste om te proberen is om een ​​dure query te kiezen (bijvoorbeeld een langlopende of een die vele malen per seconde wordt uitgevoerd) en een of meer van de tijdelijke tabellen te verwijderen om te zien of de prestaties verbeteren zonder deze. En als dat zo is, dan is er jouw bewijs om de onverzoenlijken te laten zien!

Probleem 2:gebrek aan filtering bij het vullen van tijdelijke tabellen

Zelfs als u een tijdelijke tabel niet kunt verwijderen, kunt u de prestaties mogelijk drastisch verbeteren door ervoor te zorgen dat de code die de tijdelijke tabel vult de gegevens uit brontabellen correct filtert.

Ik ben de tel kwijt van het aantal keren dat ik een tijdelijke tabel heb zien vullen met code die begint als SELECT * , bevat een paar onbeperkte joins en heeft geen WHERE-component, en de latere query die de tijdelijke tabel gebruikt, gebruikt slechts een paar kolommen en heeft een WHERE-component om het aantal rijen enorm te verkleinen.

Ik herinner me een geval waarin een tijdelijke tabel in een opgeslagen procedure 15 jaar aan gegevens uit de hoofddatabase verzamelde en toen alleen de gegevens van het huidige jaar werden gebruikt. Dit zorgde er herhaaldelijk voor dat tempdb groeide totdat het geen ruimte meer had op het schijfvolume, en de opgeslagen procedure zou dan mislukken.

Wanneer u een tijdelijke tabel vult, gebruik dan alleen de brontabelkolommen die nodig zijn en gebruik alleen de rijen die nodig zijn - d.w.z. duw de filterpredikaten omhoog in de tijdelijke tabelpopulatiecode. Dit bespaart niet alleen ruimte in tempdb, het zal ook veel tijd besparen doordat u geen onnodige gegevens uit de brontabel hoeft te kopiëren (en mogelijk de noodzaak om brondatabasepagina's in de eerste plaats van schijf te lezen) wegneemt.

Probleem 3:Onjuiste tijdelijke tabelindexering

Net als bij gewone tabellen, moet u alleen de indexen maken die daadwerkelijk door de latere querycode worden gebruikt om de queryprestaties te verbeteren. Ik heb veel gevallen gezien waarin er een niet-geclusterde index per tijdelijke tabelkolom is, en indexen met één kolom die worden gekozen zonder de latere code te analyseren, zijn vaak behoorlijk nutteloos. Combineer nu nutteloze niet-geclusterde indexen met een gebrek aan filtering bij het vullen van de tijdelijke tabel, en je hebt een recept voor een enorm opgeblazen gevoel van tempdb.

Over het algemeen is het ook sneller om de indexen te maken nadat de tabel is gevuld. Dit geeft de toegevoegde bonus dat de indexen nauwkeurige statistieken zullen hebben, die de zoekopdracht verder kunnen helpen, aangezien de query-optimizer in staat zal zijn om nauwkeurige kardinaliteitsschattingen uit te voeren.

Het hebben van een aantal niet-geclusterde indexen die niet worden gebruikt, verspilt niet alleen schijfruimte, maar ook de tijd die nodig is om ze te maken. Als dit in code is die vaak wordt uitgevoerd, kan het verwijderen van deze onnodige indexen die elke keer dat de code wordt gemaakt, een aanzienlijk effect hebben op de algehele prestaties.

Probleem 4:tempdb vergrendelingsconflict

Het is vrij gebruikelijk dat er een blijvend knelpunt is in tempdb dat terug te voeren is op tijdelijk tafelgebruik. Als er veel gelijktijdige verbindingen zijn met code die tijdelijke tabellen maakt en verwijdert, kan toegang tot de toewijzingsbitmaps van de database in het geheugen een belangrijk knelpunt worden.

Dit komt omdat slechts één thread tegelijk een toewijzingsbitmap kan wijzigen om pagina's (uit de tijdelijke tabel) te markeren als toegewezen of niet-toegewezen, en dus moeten alle andere threads wachten, waardoor de doorvoer van de werklast afneemt. Ook al is er sinds SQL Server 2005 een tijdelijke tabelcache, deze is niet erg groot en er zijn beperkingen voor wanneer de tijdelijke tabel in de cache kan worden opgeslagen (bijvoorbeeld alleen wanneer deze kleiner is dan 8 MB).

Traditionele manieren om dit probleem te omzeilen waren het gebruik van traceringsvlag 1118 en meerdere tempdb-gegevensbestanden (zie deze blogpost voor meer informatie), maar een ander ding om te overwegen is om de tijdelijke tabellen helemaal te verwijderen!

Samenvatting

Tijdelijke tabellen kunnen erg handig zijn, maar ze worden heel gemakkelijk en vaak verkeerd gebruikt. Overweeg het volgende wanneer u code schrijft (of beoordeelt) die een tijdelijke tabel gebruikt:

  • Is deze tijdelijke tafel echt nodig ?
  • Is de code die de tabel vult met de juiste filtering om de tijdelijke tafelgrootte te beperken?
  • Worden indexen gemaakt na populatie van tabellen (in het algemeen) en worden de indexen gebruikt door latere code?

Paul White heeft een aantal geweldige berichten (hier en hier) over tijdelijk gebruik van objecten en caching die ik ook aanraad om te lezen.

En een laatste ding, als u besluit geen tijdelijke tabel te gebruiken, vervang deze dan niet alleen door een tabelvariabele, een algemene tabeluitdrukking of een cursor (dit zijn allemaal gebruikelijke manieren waarop mensen proberen de tijdelijke tabel) - zoek uit wat de meest efficiënte manier is om de code te (her)schrijven - er is geen "one size fits all"-antwoord.

Tot de volgende keer, veel plezier met het oplossen van problemen!


  1. Dynamische spil in orakel sql

  2. NEW_TIME() Functie in Oracle

  3. Itereren over integer[] in PL/pgSQL

  4. Hoe een datetime op te slaan in MySQL met tijdzone-info