sql >> Database >  >> RDS >> Database

Nieuwe traceervlag om tabelvariabele prestaties te herstellen

Het is al lang bekend dat tabelvariabelen met een groot aantal rijen problematisch kunnen zijn, omdat de optimizer ze altijd als één rij beschouwt. Zonder een hercompilatie nadat de tabelvariabele is gevuld (aangezien deze daarvoor leeg is), is er geen kardinaliteit voor de tabel, en automatische hercompilatie vindt niet plaats omdat tabelvariabelen niet eens onderworpen zijn aan een hercompileringsdrempel. Plannen zijn daarom gebaseerd op een tabelkardinaliteit van nul, niet één, maar het minimum wordt verhoogd tot één, zoals Paul White (@SQL_Kiwi) beschrijft in dit dba.stackexchange-antwoord.

De manier waarop we dit probleem meestal kunnen omzeilen, is door OPTION (RECOMPILE) toe te voegen naar de query die verwijst naar de tabelvariabele, waardoor de optimizer wordt gedwongen de kardinaliteit van de tabelvariabele te inspecteren nadat deze is ingevuld. Om te voorkomen dat u elke query handmatig moet wijzigen om een ​​expliciete hercompileerhint toe te voegen, is een nieuwe traceringsvlag (2453) geïntroduceerd in SQL Server 2012 Service Pack 2 en SQL Server 2014 Cumulatieve Update #3:

    KB #2952444:FIX:slechte prestaties wanneer u tabelvariabelen gebruikt in SQL Server 2012 of SQL Server 2014

Wanneer traceringsvlag 2453 actief is, kan het optimalisatieprogramma een nauwkeurig beeld krijgen van de tabelkardinaliteit nadat de tabelvariabele is gecreëerd. Dit kan A Good Thing™ zijn voor veel vragen, maar waarschijnlijk niet voor alle, en u moet weten hoe het anders werkt dan OPTION (RECOMPILE) . Het meest opvallende is dat de optimalisatie van het insluiten van parameters waar Paul White het over heeft in dit bericht plaatsvindt onder OPTION (RECOMPILE) , maar niet onder deze nieuwe traceringsvlag.

Een eenvoudige test

Mijn eerste test bestond uit het invullen van een tabelvariabele en het selecteren ervan; dit leverde het al te bekende geschatte aantal rijen van 1 op. Hier is de test die ik heb uitgevoerd (en ik heb de hercompileerhint toegevoegd om te vergelijken):

DBCC TRACEON(2453);
 
DECLARE @t TABLE(id INT PRIMARY KEY, name SYSNAME NOT NULL UNIQUE);
 
INSERT @t SELECT TOP (1000) [object_id], name FROM sys.all_objects;
 
SELECT t.id, t.name
  FROM @t AS t;
 
SELECT t.id, t.name
  FROM @t AS t OPTION (RECOMPILE);
 
DBCC TRACEOFF(2453);

Met SQL Sentry Plan Explorer kunnen we zien dat het grafische plan voor beide query's in dit geval identiek is, waarschijnlijk ten minste gedeeltelijk omdat dit letterlijk een triviaal plan is:


Grafisch plan voor een triviale indexscan tegen @t

De schattingen zijn echter niet hetzelfde. Hoewel de traceervlag is ingeschakeld, krijgen we nog steeds een schatting van 1 uit de indexscan als we de hercompileerhint niet gebruiken:


Schattingen vergelijken voor een triviaal plan in het overzichtsraster


Schattingen vergelijken tussen traceringsvlag (links) en opnieuw compileren (rechts)

Als je ooit persoonlijk bij me in de buurt bent geweest, kun je je waarschijnlijk het gezicht voorstellen dat ik op dit punt trok. Ik dacht zeker dat het KB-artikel het verkeerde traceringsvlagnummer vermeldde, of dat ik een andere instelling nodig had om het echt actief te laten zijn.

Benjamin Nevarez (@BenjaminNevarez) wees me er snel op dat ik het KB-artikel "Bugs die zijn opgelost in SQL Server 2012 Service Pack 2" nader moest bekijken. Hoewel ze de tekst achter een verborgen opsommingsteken onder Highlights> Relational Engine hebben verdoezeld, doet het fixlist-artikel het iets beter om het gedrag van de traceringsvlag te beschrijven dan het originele artikel (nadruk van mij):

Als een tabelvariabele wordt samengevoegd met andere tabellen in SQL Server kan dit leiden tot trage prestaties als gevolg van inefficiënte selectie van queryplannen, omdat SQL Server geen statistieken ondersteunt of het aantal rijen in een tabelvariabele bijhoudt tijdens het samenstellen van een queryplan.

Uit deze beschrijving blijkt dus dat de traceringsvlag alleen bedoeld is om het probleem aan te pakken wanneer de tabelvariabele deelneemt aan een join. (Waarom dat onderscheid niet in het oorspronkelijke artikel wordt gemaakt, heb ik geen idee.) Maar het werkt ook als we de query's wat meer werk laten doen - de bovenstaande query wordt door de optimizer als triviaal beschouwd en de traceringsvlag niet' probeer in dat geval niet eens iets te doen. Maar het zal van pas komen als op kosten gebaseerde optimalisatie wordt uitgevoerd, zelfs zonder een join; de traceringsvlag heeft gewoon geen effect op triviale plannen. Hier is een voorbeeld van een niet-triviaal plan waarbij geen join nodig is:

DBCC TRACEON(2453);
 
DECLARE @t TABLE(id INT PRIMARY KEY, name SYSNAME NOT NULL UNIQUE);
 
INSERT @t SELECT TOP (1000) [object_id], name FROM sys.all_objects;
 
SELECT TOP (100) t.id, t.name
  FROM @t AS t ORDER BY NEWID();
 
SELECT TOP (100) t.id, t.name
  FROM @t AS t ORDER BY NEWID() OPTION (RECOMPILE);
 
DBCC TRACEOFF(2453);

Dit plan is niet langer triviaal; optimalisatie is gemarkeerd als vol. Het grootste deel van de kosten wordt verplaatst naar een sorteeroperator:


Minder triviaal grafisch plan

En de schattingen komen overeen voor beide zoekopdrachten (ik zal u deze keer de tooltips besparen, maar ik kan u verzekeren dat ze hetzelfde zijn):


Statementsraster voor minder triviale plannen met en zonder de hercompileerhint

Het lijkt er dus op dat het KB-artikel niet helemaal nauwkeurig is - ik was in staat om het verwachte gedrag van de traceringsvlag af te dwingen zonder een join te introduceren. Maar ik wil het ook testen met een join.

Een betere test

Laten we dit eenvoudige voorbeeld nemen, met en zonder de traceringsvlag:

--DBCC TRACEON(2453);
 
DECLARE @t TABLE(id INT PRIMARY KEY, name SYSNAME NOT NULL UNIQUE);
 
INSERT @t SELECT TOP (1000) [object_id], name FROM sys.all_objects;
 
SELECT t.name, c.name
  FROM @t AS t
  LEFT OUTER JOIN sys.all_columns AS c
  ON t.id = c.[object_id];
 
--DBCC TRACEOFF(2453);

Zonder de traceringsvlag schat het optimalisatieprogramma dat één rij afkomstig zal zijn van de indexscan tegen de tabelvariabele. Met de traceervlag ingeschakeld, krijgt het echter de 1.000 rijen knallen:


Vergelijking van schattingen van indexscans (geen traceervlag aan de linkerkant, traceervlag aan de rechterkant)

De verschillen houden daar niet op. Als we beter kijken, kunnen we verschillende beslissingen zien die de optimizer heeft genomen, allemaal voortkomend uit deze betere schattingen:


Vergelijking van plannen (geen traceervlag aan de linkerkant, traceervlag aan de rechterkant)

Een korte samenvatting van de verschillen:

  • De query zonder de traceringsvlag heeft 4.140 leesbewerkingen uitgevoerd, terwijl de query met de verbeterde schatting slechts 424 heeft uitgevoerd (ongeveer een vermindering van 90%).
  • De optimizer schatte dat de hele query 10 rijen zou opleveren zonder de traceringsvlag, en een veel nauwkeuriger 2.318 rijen bij gebruik van de traceringsvlag.
  • Zonder de traceringsvlag heeft de optimizer ervoor gekozen om een ​​geneste loops-join uit te voeren (wat logisch is wanneer een van de invoer als zeer klein wordt geschat). Dit leidde tot de concatenatie-operator en beide index-zoekopdrachten worden 1.000 keer uitgevoerd, in tegenstelling tot de hash-overeenkomst die is gekozen onder de traceringsvlag, waarbij de concatenatie-operator en beide scans slechts één keer worden uitgevoerd.
  • Het tabblad Tabel I/O toont ook 1.000 scans (bereikscans vermomd als indexzoekacties) en een veel hogere logische leestelling tegen syscolpars (de systeemtabel achter sys.all_columns ).
  • Hoewel de duur niet significant werd beïnvloed (24 milliseconden versus 18 milliseconden), kun je je waarschijnlijk voorstellen wat voor impact deze andere verschillen kunnen hebben op een serieuzere zoekopdracht.
  • Als we het diagram overschakelen naar geschatte kosten, kunnen we zien hoe enorm verschillend de tabelvariabele de optimizer voor de gek kan houden zonder de traceringsvlag:


Geschat aantal rijen vergelijken (geen traceervlag aan de linkerkant, traceer vlag aan de rechterkant)

Het is duidelijk en niet schokkend dat de optimizer het juiste plan beter kan selecteren als hij een nauwkeurig beeld heeft van de betrokken kardinaliteit. Maar tegen welke prijs?

Hercompileert en overhead

Wanneer we OPTION (RECOMPILE) gebruiken met de bovenstaande batch, zonder de traceervlag ingeschakeld, krijgen we het volgende plan - dat vrijwel identiek is aan het plan met de traceervlag (het enige merkbare verschil is dat de geschatte rijen 2.316 zijn in plaats van 2.318):


Dezelfde zoekopdracht met OPTIE (HERCOMPIEREN)

Dit zou u dus kunnen doen geloven dat de traceringsvlag vergelijkbare resultaten behaalt door elke keer een hercompilatie voor u te activeren. We kunnen dit onderzoeken met een heel eenvoudige Extended Events-sessie:

CREATE EVENT SESSION [CaptureRecompiles] ON SERVER 
ADD EVENT sqlserver.sql_statement_recompile
  (
    ACTION(sqlserver.sql_text)
  ) 
  ADD TARGET package0.asynchronous_file_target
  (
    SET FILENAME = N'C:\temp\CaptureRecompiles.xel'
  );
GO
ALTER EVENT SESSION [CaptureRecompiles] ON SERVER STATE = START;

Ik heb de volgende reeks batches uitgevoerd, die 20 query's uitvoerden met (a) geen hercompileeroptie of traceervlag, (b) de hercompileeroptie en (c) een traceervlag op sessieniveau.

/* default - no trace flag, no recompile */
 
DECLARE @t TABLE(id INT PRIMARY KEY, name SYSNAME NOT NULL UNIQUE);
 
INSERT @t SELECT TOP (1000) [object_id], name FROM sys.all_objects;
 
SELECT t.name, c.name
  FROM @t AS t
  LEFT OUTER JOIN sys.all_columns AS c
  ON t.id = c.[object_id];
 
GO 20
 
/* recompile */
 
DECLARE @t TABLE(id INT PRIMARY KEY, name SYSNAME NOT NULL UNIQUE);
 
INSERT @t SELECT TOP (1000) [object_id], name FROM sys.all_objects;
 
SELECT t.name, c.name
  FROM @t AS t
  LEFT OUTER JOIN sys.all_columns AS c
  ON t.id = c.[object_id] OPTION (RECOMPILE);
 
GO 20
 
/* trace flag */
 
DBCC TRACEON(2453);  
 
DECLARE @t TABLE(id INT PRIMARY KEY, name SYSNAME NOT NULL UNIQUE);
 
INSERT @t SELECT TOP (1000) [object_id], name FROM sys.all_objects;
 
SELECT t.name, c.name
  FROM @t AS t
  LEFT OUTER JOIN sys.all_columns AS c
  ON t.id = c.[object_id];
 
DBCC TRACEOFF(2453);
 
GO 20

Toen keek ik naar de gebeurtenisgegevens:

SELECT 
  sql_text = LEFT(sql_text, 255),
  recompile_count = COUNT(*)
FROM 
(
  SELECT 
    x.x.value(N'(event/action[@name="sql_text"]/value)[1]',N'nvarchar(max)')
  FROM 
    sys.fn_xe_file_target_read_file(N'C:\temp\CaptureRecompiles*.xel',NULL,NULL,NULL) AS f
    CROSS APPLY (SELECT CONVERT(XML, f.event_data)) AS x(x)
) AS x(sql_text)
GROUP BY LEFT(sql_text, 255);

De resultaten laten zien dat er geen hercompilaties hebben plaatsgevonden onder de standaardquery, de instructie die verwijst naar de tabelvariabele is eenmaal opnieuw gecompileerd onder de traceervlag en, zoals je zou verwachten, elke keer met de RECOMPILE optie:

sql_text recompile_count
/* hercompileer */ DECLARE @t TABLE (i INT … 20
/* traceervlag */ DBCC TRACEON(2453); VERKLAREN @t … 1

Resultaten van zoekopdracht tegen XEvents-gegevens

Vervolgens zette ik de Extended Events-sessie uit en wijzigde ik de batch om op schaal te meten. In wezen meet de code 1.000 herhalingen van het maken en vullen van een tabelvariabele, en selecteert vervolgens de resultaten ervan in een #temp-tabel (een manier om de uitvoer van zoveel wegwerpresultatensets te onderdrukken), met behulp van elk van de drie methoden.

SET NOCOUNT ON;
 
/* default - no trace flag, no recompile */
 
SELECT SYSDATETIME();
GO
DECLARE @t TABLE(id INT PRIMARY KEY, name SYSNAME NOT NULL UNIQUE);
 
INSERT @t SELECT TOP (1000) [object_id], name FROM sys.all_objects;
 
SELECT t.id, c.name
  INTO #x
  FROM @t AS t
  LEFT OUTER JOIN sys.all_columns AS c
  ON t.id = c.[object_id];
 
DROP TABLE #x;
 
GO 1000
SELECT SYSDATETIME();
GO
 
 
/* recompile */
 
DECLARE @t TABLE(id INT PRIMARY KEY, name SYSNAME NOT NULL UNIQUE);
 
INSERT @t SELECT TOP (1000) [object_id], name FROM sys.all_objects;
 
SELECT t.id, c.name
  INTO #x
  FROM @t AS t
  LEFT OUTER JOIN sys.all_columns AS c
  ON t.id = c.[object_id] OPTION (RECOMPILE);
 
DROP TABLE #x;
 
GO 1000
SELECT SYSDATETIME();
GO
 
 
/* trace flag */
 
DBCC TRACEON(2453);  
 
DECLARE @t TABLE(id INT PRIMARY KEY, name SYSNAME NOT NULL UNIQUE);
 
INSERT @t SELECT TOP (1000) [object_id], name FROM sys.all_objects;
 
SELECT t.id, c.name
  INTO #x
  FROM @t AS t
  LEFT OUTER JOIN sys.all_columns AS c
  ON t.id = c.[object_id];
 
DROP TABLE #x;
 
DBCC TRACEOFF(2453);  
 
GO 1000
SELECT SYSDATETIME();
GO

Ik heb deze batch 10 keer uitgevoerd en de gemiddelden genomen; ze waren:

Methode Gemiddelde duur
(milliseconden)
Standaard 23.148,4
Hercompileren 29.959.3
Vlag traceren 22.100.7

Gemiddelde duur voor 1000 herhalingen

In dit geval was het verkrijgen van de juiste schattingen elke keer dat de hercompileerhint werd gebruikt veel langzamer dan het standaardgedrag, maar het gebruik van de traceringsvlag was iets sneller. Dit is logisch omdat - hoewel beide methoden het standaardgedrag van het gebruik van een valse schatting corrigeren (en als gevolg daarvan een slecht plan krijgen), hercompilaties middelen vergen en, wanneer ze geen efficiënter plan kunnen of kunnen opleveren, de neiging hebben om bijdragen aan de totale batchduur.

Lijkt eenvoudig, maar wacht...

De bovenstaande test is enigszins - en opzettelijk - gebrekkig. We voegen elke keer hetzelfde aantal rijen (1.000) in de tabelvariabele in . Wat gebeurt er als de initiële populatie van de tabelvariabele varieert voor verschillende batches? We zullen dan zeker hercompilaties zien, zelfs onder de trace-vlag, toch? Tijd voor een nieuwe test. Laten we een iets andere Extended Events-sessie opzetten, alleen met een andere doelbestandsnaam (om geen gegevens van de andere sessie door elkaar te halen):

CREATE EVENT SESSION [CaptureRecompiles_v2] ON SERVER 
ADD EVENT sqlserver.sql_statement_recompile
  (
    ACTION(sqlserver.sql_text)
  ) 
  ADD TARGET package0.asynchronous_file_target
  (
    SET FILENAME = N'C:\temp\CaptureRecompiles_v2.xel'
  );
GO
ALTER EVENT SESSION [CaptureRecompiles_v2] ON SERVER STATE = START;

Laten we nu deze batch inspecteren en rijtellingen instellen voor elke iteratie die aanzienlijk verschillen. We zullen dit drie keer uitvoeren, waarbij we de juiste opmerkingen verwijderen, zodat we één batch hebben zonder traceringsvlag of expliciete hercompilatie, één batch met de traceringsvlag en één batch met OPTION (RECOMPILE) (door een nauwkeurige opmerking aan het begin te maken, zijn deze batches gemakkelijker te identificeren op plaatsen zoals de uitvoer van uitgebreide gebeurtenissen):

/* default, no trace flag or recompile */
/* recompile */
/* trace flag */
 
DECLARE @i INT = 1;
 
WHILE @i <= 6
BEGIN
  --DBCC TRACEON(2453); -- uncomment this for trace flag
 
  DECLARE @t TABLE(id INT PRIMARY KEY);
 
  INSERT @t SELECT TOP (CASE @i 
      WHEN 1 THEN 24
	  WHEN 2 THEN 1782
	  WHEN 3 THEN 1701
	  WHEN 4 THEN 12
	  WHEN 5 THEN 15
	  WHEN 6 THEN 1560 
	END) [object_id]
    FROM sys.all_objects;
 
  SELECT t.id, c.name
    FROM @t AS t
    INNER JOIN sys.all_objects AS c
    ON t.id = c.[object_id]
    --OPTION (RECOMPILE); -- uncomment this for recompile
 
  --DBCC TRACEOFF(2453); -- uncomment this for trace flag
 
  DELETE @t;
  SET @i += 1;
END

Ik heb deze batches uitgevoerd in Management Studio, ze afzonderlijk geopend in Plan Explorer en de overzichtsstructuur gefilterd op alleen de SELECT vraag. We kunnen het verschillende gedrag in de drie batches zien door naar geschatte en werkelijke rijen te kijken:


Vergelijking van drie batches, kijkend naar geschatte versus werkelijke rijen
In het meest rechtse raster kunt u duidelijk zien waar hercompilaties niet hebben plaatsgevonden onder de traceringsvlag

We kunnen de XEvents-gegevens controleren om te zien wat er werkelijk is gebeurd met het opnieuw compileren:

SELECT 
  sql_text = LEFT(sql_text, 255),
  recompile_count = COUNT(*)
FROM 
(
  SELECT 
    x.x.value(N'(event/action[@name="sql_text"]/value)[1]',N'nvarchar(max)')
  FROM 
    sys.fn_xe_file_target_read_file(N'C:\temp\CaptureRecompiles_v2*.xel',NULL,NULL,NULL) AS f
    CROSS APPLY (SELECT CONVERT(XML, f.event_data)) AS x(x)
) AS x(sql_text)
GROUP BY LEFT(sql_text, 255);

Resultaten:

sql_text recompile_count
/* hercompileer */ DECLARE @i INT =1; TERWIJL ... 6
/* traceringsvlag */ DECLARE @i INT =1; TERWIJL ... 4

Resultaten van zoekopdracht tegen XEvents-gegevens

Heel interessant! Onder de trace-vlag zien we *do* hercompilaties, maar alleen wanneer de waarde van de runtime-parameter aanzienlijk is afgeweken van de waarde in de cache. Wanneer de runtime-waarde anders is, maar niet veel, krijgen we geen hercompilatie en worden dezelfde schattingen gebruikt. Het is dus duidelijk dat de traceringsvlag een hercompileringsdrempel introduceert voor tabelvariabelen, en ik heb bevestigd (via een afzonderlijke test) dat dit hetzelfde algoritme gebruikt als dat beschreven voor #temp-tabellen in dit "oude" maar nog steeds relevante artikel. Ik zal dit in een vervolgpost bewijzen.

We zullen opnieuw de prestaties testen, de batch 1000 keer uitvoeren (met de Extended Events-sessie uitgeschakeld) en de duur meten:

Methode Gemiddelde duur
(milliseconden)
Standaard 101.285.4
Hercompileren 111.423.3
Vlag traceren 110.318.2

Gemiddelde duur voor 1000 herhalingen

In dit specifieke scenario verliezen we ongeveer 10% van de prestaties door elke keer opnieuw te compileren of door een traceringsvlag te gebruiken. Niet precies zeker hoe de delta was verdeeld:Waren de plannen gebaseerd op betere schattingen niet aanzienlijk beter? Compenseerden hercompilaties de prestatieverbeteringen met zoveel ? Ik wil hier niet te veel tijd aan besteden, en het was een triviaal voorbeeld, maar het laat zien dat spelen met de manier waarop de optimizer werkt een onvoorspelbare aangelegenheid kan zijn. Soms ben je misschien beter af met het standaardgedrag van kardinaliteit =1, wetende dat je nooit onnodige hercompilaties zult veroorzaken. Waar de traceringsvlag heel logisch kan zijn, is als u query's hebt waarbij u herhaaldelijk tabelvariabelen vult met dezelfde set gegevens (bijvoorbeeld een opzoektabel voor postcodes) of als u altijd 50 of 1.000 rijen gebruikt (bijvoorbeeld een tabelvariabele voor gebruik bij paginering). In ieder geval moet u zeker de impact testen die dit heeft op elke werklast waarbij u van plan bent de traceringsvlag of expliciete hercompilaties te introduceren.

TVP's en tabeltypen

Ik was ook benieuwd hoe dit van invloed zou zijn op tabeltypen en of we verbeteringen zouden zien in kardinaliteit voor TVP's, waar hetzelfde symptoom bestaat. Dus heb ik een eenvoudig tabeltype gemaakt dat de tot nu toe gebruikte tabelvariabele nabootst:

USE MyTestDB;
GO
 
CREATE TYPE dbo.t AS TABLE 
(
  id INT PRIMARY KEY
);

Daarna nam ik de bovenstaande batch en verving ik eenvoudig DECLARE @t TABLE(id INT PRIMARY KEY); met DECLARE @t dbo.t; – al het andere bleef precies hetzelfde. Ik heb dezelfde drie batches uitgevoerd en dit is wat ik zag:


Vergelijking van schattingen en werkelijke waarden tussen standaardgedrag, hercompileren van opties en traceringsvlag 2453

Dus ja, het lijkt erop dat de traceringsvlag op exact dezelfde manier werkt met TVP's:hercompilaties genereren nieuwe schattingen voor de optimizer wanneer het aantal rijen de hercompilatiedrempel overschrijdt, en worden overgeslagen wanneer het aantal rijen "dicht genoeg bij elkaar ligt".

Voors, tegens en waarschuwingen

Een voordeel van de traceervlag is dat u sommige . kunt vermijden hercompileert en ziet nog steeds tabelkardinaliteit - zolang u verwacht dat het aantal rijen in de tabelvariabele stabiel zal zijn, of geen significante planafwijkingen waarneemt als gevolg van variërende kardinaliteit. Een andere is dat u het globaal of op sessieniveau kunt inschakelen en dat u geen hercompileerhints hoeft te introduceren voor al uw vragen. En tot slot, in het geval dat de kardinaliteit van tabelvariabelen stabiel was, leidden goede schattingen tot betere prestaties dan de standaard, en ook betere prestaties dan het gebruik van de hercompilatieoptie - al die compilaties kunnen zeker kloppen.

Er zijn natuurlijk ook wat nadelen. Een die ik hierboven noemde, is die in vergelijking met OPTION (RECOMPILE) je loopt bepaalde optimalisaties mis, zoals het inbedden van parameters. Een andere is dat de traceringsvlag niet de impact heeft die u verwacht op triviale plannen. En een die ik onderweg ontdekte, is dat het gebruik van de QUERYTRACEON hint om de traceringsvlag op queryniveau af te dwingen werkt niet - voor zover ik weet, moet de traceringsvlag aanwezig zijn wanneer de tabelvariabele of TVP wordt gemaakt en/of ingevuld, zodat de optimizer de kardinaliteit hierboven kan zien 1.

Houd er rekening mee dat het globaal uitvoeren van de traceringsvlag de mogelijkheid introduceert van queryplanregressies voor elke query waarbij een tabelvariabele is betrokken (daarom is deze functie in de eerste plaats geïntroduceerd onder een traceringsvlag), dus zorg ervoor dat u uw volledige werkbelasting test ongeacht hoe u de traceringsvlag gebruikt. Als u dit gedrag test, doe dit dan ook in een gebruikersdatabase; sommige van de optimalisaties en vereenvoudigingen die u normaal gesproken verwacht, gebeuren gewoon niet wanneer de context is ingesteld op tempdb, dus elk gedrag dat u daar waarneemt, blijft mogelijk niet consistent wanneer u de code en instellingen naar een gebruikersdatabase verplaatst.

Conclusie

Als u tabelvariabelen of TVP's met een groot maar relatief consistent aantal rijen gebruikt, kan het nuttig zijn om deze traceringsvlag voor bepaalde batches of procedures in te schakelen om nauwkeurige tabelkardinaliteit te krijgen zonder handmatig een hercompilatie van afzonderlijke query's te forceren. U kunt ook de traceringsvlag op instantieniveau gebruiken, die van invloed is op alle query's. Maar zoals bij elke wijziging, moet u in beide gevallen ijverig zijn in het testen van de prestaties van uw volledige werkbelasting, expliciet uitkijken naar eventuele regressies en ervoor zorgen dat u het traceervlaggedrag wilt omdat u kunt vertrouwen op de stabiliteit van uw tabelvariabele rij telt.

Ik ben blij om te zien dat de traceringsvlag is toegevoegd aan SQL Server 2014, maar het zou beter zijn als dat gewoon het standaardgedrag werd. Niet dat er een significant voordeel is aan het gebruik van grote tabelvariabelen ten opzichte van grote #temp-tabellen, maar het zou leuk zijn om meer pariteit te zien tussen deze twee tijdelijke structuurtypen die op een hoger niveau zouden kunnen worden gedicteerd. Hoe meer gelijkheid we hebben, hoe minder mensen hoeven te overleggen welke ze moeten gebruiken (of in ieder geval minder criteria om te overwegen bij het kiezen). Martin Smith heeft een geweldige vraag en antwoord op dba.stackexchange die nu waarschijnlijk aan een update toe is:wat is het verschil tussen een tijdelijke tabel en een tabelvariabele in SQL Server?

Belangrijke opmerking

Als je SQL Server 2012 Service Pack 2 gaat installeren (al dan niet om gebruik te maken van deze traceringsvlag), zie dan ook mijn post over een regressie in SQL Server 2012 en 2014 die – in zeldzame gevallen – kan leiden tot mogelijk gegevensverlies of corruptie tijdens het opnieuw opbouwen van de online index. Er zijn cumulatieve updates beschikbaar voor SQL Server 2012 SP1 en SP2 en ook voor SQL Server 2014. Er zal geen oplossing zijn voor de 2012 RTM-tak.

Verdere testen

Ik heb nog andere dingen op mijn lijst om te testen. Ten eerste zou ik graag willen zien of deze traceringsvlag enig effect heeft op In-Memory-tabeltypen in SQL Server 2014. Ik ga ook zonder enige twijfel bewijzen dat traceringsvlag 2453 dezelfde hercompilatiedrempel gebruikt voor tabel variabelen en TVP's zoals voor #temp-tabellen.


  1. Er is een netwerkgerelateerde of instantiespecifieke fout opgetreden bij het tot stand brengen van een verbinding met SQL Server

  2. Postgres ontbreekt FROM-clausule invoerfout bij query met WITH-component

  3. Korte post over de SQLite UPSERT en de nieuwe RETURNING-clausule.

  4. Vraag laatste N gerelateerde rijen per rij op