sql >> Database >  >> RDS >> Sqlserver

Interne SQL Server:Plan Caching Pt. I – Plannen hergebruiken

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.

Bekijk hier de recente blogs van Kalen over Problematic Operators.

Plannen voor diagnostiek van SQL-servers kunnen duur zijn om te maken, omdat de query-optimizer een goed plan moet kunnen vinden voor elke juridische vraag die wordt ingediend. De optimizer evalueert meerdere samenvoegvolgorde, meerdere indexen. en verschillende soorten samenvoegings- en groeperingsalgoritmen, afhankelijk van uw zoekopdracht en de betrokken tabellen. Als dezelfde query opnieuw wordt uitgevoerd, kan SQL Server veel resources besparen door een bestaand abonnement opnieuw te gebruiken. Maar het is niet altijd mogelijk om een ​​bestaand plan te hergebruiken, en het is ook niet altijd goed om dat te doen. In de volgende twee artikelen bekijken we wanneer een plan opnieuw wordt gebruikt en wanneer het opnieuw wordt gecompileerd.

Eerst zullen we kijken naar de verschillende smaken van plannen en de metadataweergave die ik het vaakst gebruik om te kijken naar wat er in mijn plancache zit. Ik heb een eigen visie geschreven die de informatie geeft die ik het meest nuttig vind. SQL Server slaat zes verschillende typen queryplannen op in de cache, maar er worden er normaal gesproken slechts twee gebruikt voor het afstemmen van de cachecache. Dit zijn SAMENGESTELDE PLAN en SAMENGESTELDE PLAN STUB. Mijn weergave filtert alles behalve deze twee soorten cache-objecten. SAMENGESTELDE PLANNEN zijn er in drie varianten:AD HOC, PREPARED en PROC. Ik zal op alle drie de soorten reageren.

Zelfs als we alleen maar naar SAMENGESTELDE PLANNEN kijken, zijn er nog steeds veel plannen in de cache die meestal moeten worden genegeerd, omdat ze door SQL Server zelf worden gegenereerd. Deze omvatten plannen die zoeken naar bestandsstream- of full-text zoekindexen of interne zoekopdrachten die werken met In-memory OLTP. Dus mijn weergave voegt filters toe om te proberen de meeste plannen waar ik niet in geïnteresseerd ben, uit te schakelen. Je kunt een script downloaden om deze weergave te bouwen, genaamd sp_cacheobjects , van hier.

Zelfs met alle filters die mijn weergave gebruikt, zijn er nog steeds enkele interne query's van SQL Server in de cache; Ik wis de plancache meestal regelmatig wanneer ik op dit gebied test. De eenvoudigste manier om ALLE plannen uit de cache te wissen is met het commando:DBCC FREEPROCCACHE.

Adhoc samengestelde plannen

Het eenvoudigste type abonnement is Adhoc. Dit wordt gebruikt voor basisquery's die niet in een andere categorie passen. Als je mijn script hebt gedownload en mijn sp_cacheobjects-weergave hebt gemaakt, kun je het volgende uitvoeren. Elke versie van de AdventureWorks-database zou moeten werken. Dit script maakt een kopie van een tabel en bouwt er een aantal unieke indexen op. Het masseert ook het subtotaalbedrag om eventuele decimale cijfers te verwijderen.

USE AdventureWorks2016;
GO
DROP TABLE IF EXISTS newsales;
GO
-- Make a copy of the Sales.SalesOrderHeader table
SELECT * INTO dbo.newsales
FROM Sales.SalesOrderHeader;
GO
UPDATE dbo.newsales
SET SubTotal = cast(cast(SubTotal as int) as money);
GO
CREATE UNIQUE index newsales_ident
    ON newsales(SalesOrderID);
GO
CREATE INDEX IX_Sales_SubTotal ON newsales(SubTotal);
GO
-- Adhoc query plan reuse
DBCC FREEPROCCACHE;
GO
-- adhoc query
SELECT * FROM dbo.newsales
WHERE SubTotal = 4;
GO
SELECT * FROM sp_cacheobjects;
GO

In mijn output zie je twee Adhoc-plannen. Een daarvan is voor de SELECT-instructie van de newsales tabel, en de andere is voor de SELECT uit mijn sp_cacheobjects weergave. Omdat het plan in de cache is opgeslagen en de EXACT dezelfde query opnieuw wordt uitgevoerd, kan hetzelfde plan opnieuw worden gebruikt en ziet u de usecounts waarde verhogen. Er is echter een vangst. Om een ​​Adhoc-plan opnieuw te kunnen gebruiken, moet de SQL-string absoluut exact hetzelfde zijn. Als u tekens in de SQL wijzigt, wordt de query niet herkend als dezelfde query en wordt er een nieuw plan gegenereerd. Als ik zelfs een spatie toevoeg, de opmerking of een nieuw regeleinde toevoeg, is het niet dezelfde tekenreeks. Als ik de case verander, betekent dat dat er verschillende ASCII-codewaarden zijn, dus niet dezelfde string.

Je kunt dit zelf uitproberen door verschillende varianten van mijn eerste SELECT-statement uit te voeren vanuit de newsales tafel. Je ziet voor elke rij een andere rij in de cache. Nadat ik verschillende variaties had uitgevoerd - het nummer wijzigen waarnaar ik op zoek was, de hoofdlettergebruik wijzigen, de opmerking toevoegen en een nieuwe regel, zie ik het volgende in de cache. De SELECT wordt naar mijn mening hergebruikt, maar al het andere heeft een usecounts waarde van 1.

Een extra vereiste voor hergebruik van Adhoc-queryplannen is dat de sessie die de query uitvoert dezelfde SET-opties moet hebben . Er is nog een kolom in de uitvoer die u rechts van de vraagtekst kunt zien, genaamd SETOPTS. Dit is een bitstring met een bit voor elke relevante SET-optie. Als u een van de opties wijzigt, bijvoorbeeld SET ANSI_NULLS OFF, verandert de bitstring en kan hetzelfde plan met de originele bitstring niet opnieuw worden gebruikt.

Voorbereide samengestelde plannen

Het tweede type gecompileerd plan in de cache is een VOORBEREID plan. Als uw vraag aan een aantal eisen voldoet. Het kan zelfs automatisch worden geparametriseerd. Het verschijnt in de metadata als VOORBEREID en de SQL-string toont een parametermarkering. Hier is een voorbeeld:

Het VOORBEREID plan toont de parametermarkering als @1 en bevat niet de werkelijke waarde. Merk op dat er een rij is voor een ADHOC-query met een werkelijke waarde van 5555, maar dat is eigenlijk slechts een 'schil' van de echte query. Het slaat niet het hele plan op in de cache, maar alleen de query en een paar identificerende details, om de queryprocessor te helpen het geparametreerde plan in de cache te vinden. Let op de grootte (pagesused ) is veel kleiner dan het VOORBEREID abonnement.

De standaard parametreermodus, SIMPLE-parametrering genoemd, is extreem streng over welke plannen kunnen worden geparametriseerd. Het zijn eigenlijk alleen de eenvoudigste query's die standaard parametreerbaar zijn. Query's die JOIN, GROUP BY, OR en vele andere relatief veel voorkomende queryconstructies bevatten, voorkomen dat een query wordt geparametriseerd. Naast het ontbreken van een van deze constructies, is het belangrijkste voor SIMPLE-parametrering dat de query VEILIG is. Dit betekent dat er maar één mogelijk plan is, ongeacht de waarden die voor parameters worden doorgegeven. (Natuurlijk kan een zoekopdracht zonder parameters ook VEILIG zijn.) Mijn zoekopdracht zoekt naar een exacte overeenkomst in de kolom SalesOrderID , die een unieke index heeft. Dus de bestaande niet-geclusterde index kan worden gebruikt om elke overeenkomende rij te vinden. Welke waarde ik ook gebruik, 55555 of iets anders, er zal nooit meer dan één rij zijn, wat betekent dat het plan nog steeds goed is.

In het voorbeeld van mijn Adhoc-queryplan was ik op zoek naar overeenkomende waarden voor SubTotaal . Sommige Subtotaal waarden komen een paar keer of helemaal niet voor, dus een niet-geclusterde index zou goed zijn. Maar andere waarden kunnen vele malen voorkomen, dus de index zou NIET nuttig zijn. Het queryplan is dus niet VEILIG en de query kan niet worden geparametriseerd. Daarom zagen we een adhoc-plan voor mijn eerste voorbeeld.

ALS u query's hebt met JOIN of andere niet-toegestane constructies, kunt u SQL Server vertellen agressiever te zijn in het parametreren door een database-optie te wijzigen:

ALTER DATABASE AdventureWorks2016 SET parameterization FORCED;
GO

Het instellen van uw database op GEFORCEERDE parametrering betekent dat SQL Server een heleboel meer query's zal parametreren, inclusief die met JOIN, GROUP BY, OR, enz. Maar het betekent ook dat SQL Server een query kan parametriseren die niet VEILIG is. Het kan een plan bedenken dat goed is als er maar een paar rijen worden geretourneerd, en het plan vervolgens opnieuw gebruiken als er veel rijen worden geretourneerd. Dit kan leiden tot zeer suboptimale prestaties.

Een laatste optie voor een voorbereid plan is wanneer u expliciet een plan opstelt. Dit gedrag wordt meestal aangeroepen via een applicatie met SQLPrepare en SQLEexecute API's. U specificeert wat de query is met parametermarkeringen, u specificeert de gegevenstypen en u geeft de specifieke waarden op die moeten worden gebruikt. Dezelfde query kan dan opnieuw worden uitgevoerd met verschillende specifieke waarden en het bestaande plan zal worden gebruikt. Hoewel het gebruik van expliciet opgestelde plannen kan zijn voor die gevallen waarin SQL Server niet parametriseert en u dat zou willen, belet dit niet dat SQL Server een plan gebruikt dat NIET goed is voor latere parameters. U moet uw zoekopdrachten testen met veel verschillende invoerwaarden en ervoor zorgen dat u de verwachte prestaties krijgt als en wanneer een plan opnieuw wordt gebruikt.

De metadata (bijv. mijn sp_cacheobjects weergave) toont alleen VOORBEREID voor alle drie de soorten plannen:GEDWONGEN en EENVOUDIGE autoparameterisatie en EXPLICIETE parametrering.

Proc samengestelde plannen

Het laatste objecttype waarde voor gecompileerde plannen is voor een opgeslagen procedure, die wordt weergegeven als Proc. Indien mogelijk zijn opgeslagen procedures de beste keuze voor herbruikbare code, vanwege het gemak waarmee ze vanaf de server zelf kunnen worden beheerd, maar dat betekent niet dat ze gegarandeerd altijd de beste prestaties leveren. Net als het gebruik van de FORCED-parameteroptie (en ook de expliciete parametrering), gebruiken opgeslagen procedures 'parameter sniffing'. Dit betekent dat de eerste ingevoerde parameterwaarde het plan bepaalt. Als opeenvolgende uitvoeringen prima presteren met hetzelfde plan, dan is het snuiven van parameters geen probleem en kan het zelfs voordelig zijn omdat het ons de kosten van hercompileren en heroptimaliseren bespaart. Als volgende uitvoeringen met verschillende waarden echter niet het oorspronkelijke plan zouden moeten gebruiken, hebben we een probleem. Ik zal je een voorbeeld laten zien van het snuiven van parameters dat een probleem veroorzaakt

Ik zal een opgeslagen procedure maken op basis van de nieuweverkoop tafel die we eerder gebruikten. De procedure heeft een enkele query, die filtert op basis van de SalesOrderID kolom, waarop we een niet-geclusterde index hebben gebouwd. De query is gebaseerd op een ongelijkheid, dus voor sommige waarden kan de query slechts een paar rijen retourneren en de index gebruiken, en voor andere waarden kan de query VEEL rijen retourneren. Met andere woorden, de zoekopdracht is niet VEILIG.

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

Ik gebruik de optie STATISTIEKEN INSTELLEN IO AAN om te zien hoeveel werk er wordt verzet wanneer de procedure wordt uitgevoerd. Eerst zal ik het uitvoeren met een parameter die slechts een paar rijen retourneert:

SET STATISTICS IO ON
GO
EXEC get_sales_range 43700;
GO

De STATISTICS IO-waarde meldt dat er 43 logische leesbewerkingen nodig waren om 41 rijen te retourneren. Dit is normaal voor een niet-geclusterde index. Nu voeren we de procedure opnieuw uit met een veel grotere waarde.

EXEC get_sales_range 66666;
GO
SELECT * FROM sp_cacheobjects;
GO
This time, we see that SQL Server used a whole lot more reads:

In feite een tabelscan op de nieuwe verkoop table duurt slechts 843 reads, dus dit is veel slechtere prestatie dan een tabelscan. De sp_cacheobjects view laat zien dat het PROC-plan is hergebruikt voor deze tweede uitvoering. Dit is een voorbeeld van wanneer het snuiven van parameters GEEN goede zaak is.

Dus, wat kunnen we doen als het snuiven van parameters een probleem is? In de volgende post zal ik je vertellen wanneer SQL Server met een nieuw plan komt en oude niet opnieuw gebruikt. We zullen bekijken hoe u hercompilatie kunt forceren (of aanmoedigen), en we zullen ook zien wanneer SQL Server uw zoekopdrachten automatisch opnieuw compileert.

Spotlight Cloud kan een revolutie teweegbrengen in uw prestatiebewaking en SQL-serverdiagnostiek. Ga aan de slag met uw gratis proefversie via de onderstaande link:


  1. Typische WordPress-fouten herstellen

  2. Hoe de PostgreSQL-versie te controleren

  3. Vraag een parameter op (postgresql.conf-instelling) zoals max_connections

  4. PostgreSQL, bestaande tabel opnieuw configureren, primaire sleutel wijzigen in type=serial