sql >> Database >  >> RDS >> Sqlserver

Interne SQL Server:Plan Caching Pt. II – Plannen opnieuw compileren

Dit maakt deel uit van een serie SQL Server Internals Plan Caching. Zorg ervoor dat je Kalen's eerste bericht over dit onderwerp leest.

SQL Server bestaat al meer dan 30 jaar en ik werk al bijna net zo lang met SQL Server. Ik heb in de loop der jaren (en decennia!) en versies van dit ongelooflijke product veel veranderingen gezien. In deze berichten zal ik met u delen hoe ik kijk naar enkele van de functies of aspecten van SQL Server, soms samen met een beetje historisch perspectief

In mijn vorige artikel , Ik had het over SQL-serverdiagnostiek, inclusief de verschillende opties die SQL Server heeft voor het hergebruiken van een queryplan. We hebben gekeken naar drie soorten queryplannen:ad-hoc, voorbereid en procedure. Ik eindigde de discussie met een blik op een ongepast hergebruik van een plan, wat kan gebeuren wanneer SQL Server parameter sniffing toepast in de verkeerde situaties. Als een plan is gebaseerd op een initiële waarde die ervoor zorgt dat de optimizer een plan genereert dat geschikt is voor die waarde, en hetzelfde plan wordt gebruikt voor een andere waarde, is het plan mogelijk niet langer optimaal.

Dus, wat kunnen we doen als het snuiven van parameters een probleem is? We kunnen SQL Server dwingen om met een nieuw plan te komen. Gewoonlijk noemen we het bedenken van een nieuw plan 'opnieuw compileren', maar het zou waarschijnlijk 'opnieuw optimaliseren' moeten worden genoemd. De meeste mensen gebruiken echter de term 'opnieuw compileren', dus dat is wat ik hier zal gebruiken.

Als ongepast gebruik van het snuiven van parameters een probleem is, is een eenvoudige oplossing om SQL Server gewoon te vertellen om met een nieuw plan te komen. Voor individuele instructies, zoals bij PREPARED plannen die automatisch zijn geparametriseerd, kunnen we de RECOMPILE-hint toevoegen aan een query. Met behulp van FORCED geparametriseerd (besproken in het vorige artikel), wordt deze query geparametriseerd.

SELECT * FROM dbo.newsales 
WHERE SalesOrderID < @num;

Als we er zeker van willen zijn dat we elke keer dat we deze query uitvoeren een nieuw plan krijgen, met mogelijk enorm verschillende waarden voor @num, kunnen we de RECOMPILE-hint toevoegen zoals weergegeven:

SELECT * FROM dbo.newsales
  WHERE SalesOrderID < @num
OPTION (RECOMPILE);

Voor opgeslagen procedures hebben we drie opties. Ten eerste kunnen we vaststellen of hercompileren daadwerkelijk de prestaties zal helpen door de procedure uit te voeren met de RECOMPILE-optie:

EXEC get_sales_range 66666 WITH RECOMPILE;

Deze optie zorgt ervoor dat er alleen voor deze ene uitvoering een nieuw plan wordt gegenereerd. Het wordt niet opgeslagen en zeker niet hergebruikt. De usecount-waarde die wordt weergegeven in sp_cacheobjects (beschreven in de vorige post) voor de procedure zal niet toenemen omdat het oorspronkelijke plan niet opnieuw wordt gebruikt.

Ten tweede, als we ontdekken dat het uitvoeren MET RECOMPILE helpt, kunnen we overwegen de procedure opnieuw te maken met de RECOMPILE-optie, in welk geval het plan nooit opnieuw zal worden gebruikt en de procedure helemaal niet in de plancache zal verschijnen.

DROP PROC IF EXISTS get_sales_range;GO
CREATE PROC get_sales_range
   @num int
WITH RECOMPILE
AS
    SELECT * FROM dbo.newsales
    WHERE SalesOrderID < @num;
GO

Voor mijn eenvoudige kleine procedure kan het zinvol zijn om de optie WITH RECOMPILE voor de hele procedure te gebruiken. Maar als de procedure ingewikkelder is, heeft het misschien geen zin om de hele procedure opnieuw te compileren omdat één instructie problemen veroorzaakt. De derde optie is dus om de HERCOMPILE-hint te gebruiken voor een instructie binnen de procedure, dus het ziet er als volgt uit:

DROP PROC IF EXISTS get_sales_range;
GO
CREATE PROC get_sales_range
   @num int
AS
    SELECT * FROM dbo.newsales
    WHERE SalesOrderID < @num
    OPTION (RECOMPILE);
GO

Het gebruik van een van deze RECOMPILE-opties kan SQL Server dwingen om op uw verzoek met een nieuw plan te komen. Nu gaan we kijken wanneer uw SQL Server-diagnoseprogramma een nieuw plan bedenkt wanneer u er niet om vraagt, d.w.z. wanneer vindt automatische hercompilatie van een bestaand plan plaats?


Automatische hercompilatie van een plan vindt plaats in twee soorten situaties:

  • Ten eerste, als de optimizer vaststelt dat het bestaande plan niet langer correct is, meestal vanwege een wijziging in de objectdefinities, zal het met een nieuw plan moeten komen. Als u bijvoorbeeld een plan hebt voor een query die selecteert uit TabelA en u vervolgens meerdere kolommen laat vallen of gegevenstypes van kolommen in TabelA wijzigt, zal SQL Server de query opnieuw compileren om een ​​plan te bedenken dat de DDL-wijzigingen weerspiegelt.
  • De tweede situatie waarin automatisch hercompileren plaatsvindt, is wanneer SQL Server vaststelt dat het plan mogelijk niet langer optimaal is vanwege een wijziging in de statistieken. In de meeste gevallen, als de statistieken over een van de kolommen of indexen zijn bijgewerkt sinds de laatste keer dat het plan is samengesteld, wordt het opnieuw gecompileerd. Maar dit leidt tot een andere vraag. Wanneer worden de statistieken bijgewerkt? Statistieken kunnen automatisch worden bijgewerkt wanneer er voldoende rijen in de relevante kolommen zijn gewijzigd. Hoeveel is genoeg? Daar hebben we het straks over.

Standaard zal SQL Server de statistieken automatisch bijwerken vanwege een database-optie die standaard is ingeschakeld. Maar als u een database-eigenaar bent (of een SQL 'sa', die in elke database als de eigenaar verschijnt), kunt u de opties wijzigen. Een van de opties heet AUTO_UPDATE_STATISTICS en een andere heet AUTO_UPDATE_STATISTICS_ASYNC. De optie AUTO_UPDATE_STATISTICS is AAN in de tempdb-database, dus elke nieuwe database erft deze optie. Als deze optie is ingeschakeld en de query-uitvoeringsengine wijzigingen in een voldoende aantal rijen detecteert terwijl een query wordt verwerkt, wordt de uitvoering gepauzeerd terwijl de statistieken worden bijgewerkt en wordt de query vervolgens opnieuw gecompileerd. De andere optie, AUTO_UPDATE_STATISTICS_ASYNC, kan mogelijk minder effect hebben op de uitvoeringstijd van de query omdat de uitvoering niet wordt onderbroken, wat ten koste gaat van het gebruik van een mogelijk suboptimaal plan. Met de tweede optie, als de uitvoeringsengine de noodzaak detecteert om statistieken bij te werken, wordt een achtergrondthread gestart om de update uit te voeren, en de hoofdthread gaat door met het uitvoeren van de query met de originele statistieken en het oorspronkelijke plan. De volgende query die toegang heeft tot de betrokken tabellen en de bijgewerkte statistieken ziet, zal de query opnieuw compileren, maar deze zal niet pauzeren en de statistieken halverwege de uitvoering bijwerken.

Er zijn nog een paar situaties en enkele query-hints die bepalen of plannen al dan niet opnieuw worden gecompileerd, dus ik zal je een stroomdiagram laten zien. Ik zal een stroomschema met je delen dat ik heb gemaakt voor mijn trainingslessen over interne onderdelen van SQL Server.

De pijl is waar SQL Server begint met het verwerken van uw batch. Het controleert eerst of er al een plan voor uw batch in de cache is, en als het antwoord NEE is, volgt het de pijl naar rechts en stelt een plan op. Het plan wordt in de cache geplaatst en SQL Server start opnieuw. Ja, het plan zou deze keer in de cache moeten staan, dus dan volgt het de pijl naar beneden en vraagt ​​of een hint genaamd KEEP PLAN is gebruikt. Zo JA, dan begint SQL Server onmiddellijk met het uitvoeren van het plan en voert geen verdere controles uit.

De volgende vraag is of er DDL-wijzigingen zijn doorgevoerd. Zo nee, dan wordt er gevraagd naar verschillende andere situaties waar ik in dit artikel niet over zal kunnen praten. Sterker nog, ik ga hier echt niet alle opties doornemen. Ik laat dat aan jou over. Maar als je vragen of onduidelijkheden hebt, stel ze dan gerust in de comments hier, of tweet me op @sqlqueen. Ik zal uiterst rechts op de vraag wijzen:Staat AUTO_STATS_ASYNC AAN? Hier kunt u zien dat als het antwoord JA is, er twee acties zijn. De ene branch begint gewoon met de uitvoering met het bestaande plan, en de andere is de achtergrondthread die de statistieken bijwerkt, maar verder niets doet. De volgende vraag zal het beslissingsvenster in het midden tegenkomen "Zijn er nieuwe statistieken beschikbaar" en moet JA antwoorden, dus de vraag zal opnieuw worden gecompileerd.

Het enige andere waar ik het over zal hebben, is de vraag "Zijn statistieken verouderd?" Dit betekent in feite dat de statistieken verouderd zijn omdat er te veel wijzigingen zijn aangebracht. Dus nu kunnen we praten over hoeveel te veel is.

Hoewel er verschillende waarden worden gebruikt voor zeer kleine tabellen, zouden voor elke tabel met meer dan 500 rijen, vóór SQL Server 2016 statistieken als 'verouderd' worden beschouwd wanneer het aantal wijzigingen in de kolom waarop de statistieken waren gebaseerd meer dan 20 was. % van het aantal rijen in de tabel. Dus voor een tabel met 1000 rijen kan dit 200 invoegingen, 200 updates of 200 verwijderingen betekenen. Het kunnen 200 rijenwijzigingen zijn, of 5 rijen die elk 40 keer worden bijgewerkt. SQL Server geeft ons zelfs een functie die aangeeft hoeveel wijzigingen er zijn aangebracht. U moet het stats_id-nummer opzoeken voor de statistieken waarin u geïnteresseerd bent, wat de index_id zou zijn als de statistieken tot een index behoren. De stats_id is te vinden in de weergave genaamd sys.stats. In mijn newsales-tabel gebruik ik deze query om erachter te komen dat de stats_id voor de index in de kolom SubTotaal 3 is.

SELECT name, stats_id FROM sys.stats
WHERE object_id = object_id('newsales');

Dan kan ik die waarde gebruiken om naar het aantal wijzigingen te kijken. Laat me eerst wat rijen bijwerken:

UPDATE newsales
SET SubTotal = SubTotal * 0.9
WHERE SalesOrderID < 45200
(1541 rijen beïnvloed)

SELECT * FROM sys.dm_db_stats_properties(object_id('newsales'), 3);  

In feite is 20% een GROOT getal. En voor veel tabellen kunnen query's profiteren van bijgewerkte statistieken waarbij veel minder dan 20% van de rijen is bijgewerkt. Vanaf 2008R2 SP1 bevatte SQL Server een Traceflag die u kon gebruiken om het aantal rijen te wijzigen in een glijdende schaal, zoals weergegeven in de volgende grafiek:

Vanaf SQL Server 2016 wordt dit nieuwe algoritme met de glijdende schaal standaard gebruikt, zolang u zich in compatibiliteitsniveau 130 of hoger bevindt.

De meeste automatische hercompilaties van queryplannen zijn het gevolg van wijzigingen in statistieken. Maar zoals ik hierboven al zei, is dat niet de enige reden voor een hercompilatie. Maar aangezien dit de meest voorkomende is, kan het erg handig zijn om te weten wanneer en hoe statistieken worden bijgewerkt en ervoor te zorgen dat de statistieken op uw kritieke tabellen vaak genoeg worden bijgewerkt om ervoor te zorgen dat u de beste plannen krijgt!

Analyseer automatisch prestatiegegevens om SQL-serverdiagnose uit te voeren om problemen snel op te lossen en servers te identificeren waar prestatievermindering vandaan komt. Ga vandaag nog aan de slag met Spotlight Cloud:


  1. Fout:PLS-00428:er wordt een into-clausule verwacht in deze select-instructie

  2. Voordelen van MySQLi boven MySQL

  3. Tips voor het upgraden van Percona XtraDB Cluster naar 8.0

  4. Oracle Sequence nextval springt nummer heen en weer