Gastauteur:Derik Hammer (@SQLHammer)
Onlangs blogde Aaron Bertrand over schadelijke, doordringende mythes over SQL Server-prestaties. In het verlengde van deze blogreeks ga ik deze veelvoorkomende mythe ontkrachten:
De handleiding lezen
Ik ging rechtstreeks naar de bron en keek naar het Books Online-artikel over tabellen dat tabelvariabelen bevat. Hoewel het artikel verwijst naar de voordelen van het gebruik van tabelvariabelen, ontbreekt het opvallend dat ze 100% in het geheugen zitten.
Een ontbrekende bevestiging betekent echter niet een negatief. Sinds In-Memory OLTP-tabellen zijn uitgebracht, is er nu veel meer documentatie in BOL voor verwerking in het geheugen. Daar vond ik dit artikel over het sneller maken van tijdelijke tabel- en tabelvariabelen door geheugenoptimalisatie te gebruiken.
Het hele artikel gaat over hoe u uw tijdelijke objecten de in-memory OLTP-functie kunt laten gebruiken, en hier vond ik de bevestiging die ik zocht.
"Een traditionele tabelvariabele vertegenwoordigt een tabel in de tempdb-database. Voor veel snellere prestaties kunt u uw tabelvariabele in het geheugen optimaliseren."Tabelvariabelen zijn geen in-memory constructies. Om de in-memory-technologie te gebruiken, moet u expliciet een TYPE definiëren dat voor het geheugen is geoptimaliseerd en dat TYPE gebruiken om uw tabelvariabele te definiëren.
Bewijs het
Documentatie is één ding, maar het met eigen ogen zien is iets heel anders. Ik weet dat tijdelijke tabellen objecten maken in tempdb en gegevens naar schijf schrijven. Eerst zal ik je laten zien hoe dat eruit ziet voor de tijdelijke tabellen en daarna zal ik dezelfde methode gebruiken om de hypothese te valideren dat tabelvariabelen op dezelfde manier werken.
Analyse van logrecords
Deze query voert een CHECKPOINT uit om me een schoon startpunt te geven en toont vervolgens het aantal logrecords en de transactienamen die in het log voorkomen.
USE tempdb; GO CHECKPOINT; GO SELECT COUNT(*) [Count] FROM sys.fn_dblog (NULL, NULL); SELECT [Transaction Name] FROM sys.fn_dblog (NULL, NULL) WHERE [Transaction Name] IS NOT NULL;
Het herhaaldelijk uitvoeren van de T-SQL resulteerde in een consistente telling van drie records op SQL Server 2016 SP1.
Dit creëert een tijdelijke tabel en toont het objectrecord, wat bewijst dat dit een echt object in tempdb is.
USE tempdb; GO DROP TABLE IF EXISTS #tmp; GO CREATE TABLE #tmp (id int NULL); SELECT name FROM sys.objects o WHERE is_ms_shipped = 0;
Nu zal ik de logrecords opnieuw laten zien. Ik zal het CHECKPOINT-commando niet opnieuw uitvoeren.
Er zijn eenentwintig logrecords geschreven, wat aantoont dat dit schrijfacties op schijf zijn, en onze CREATE TABLE is duidelijk opgenomen in deze logrecords.
Om deze resultaten te vergelijken met tabelvariabelen, zal ik het experiment resetten door CHECKPOINT uit te voeren en vervolgens de onderstaande T-SQL uit te voeren, waardoor een tabelvariabele wordt gemaakt.
USE tempdb; GO DECLARE @var TABLE (id int NULL); SELECT name FROM sys.objects o WHERE is_ms_shipped = 0;
We hebben weer een nieuw objectrecord. Deze keer is de naam echter meer willekeurig dan bij tijdelijke tabellen.
Er zijn tweeëntachtig nieuwe logboekrecords en transactienamen die bewijzen dat mijn variabele naar het logboek wordt geschreven, en dus naar schijf.
Eigenlijk in het geheugen
Nu is het tijd voor mij om de logrecords te laten verdwijnen.
Ik heb een in-memory OLTP-bestandsgroep gemaakt en vervolgens een voor het geheugen geoptimaliseerd tabeltype gemaakt.
USE Test; GO CREATE TYPE dbo.inMemoryTableType AS TABLE ( id INT NULL INDEX ix1 ) WITH (MEMORY_OPTIMIZED = ON); GO
Ik heb het CHECKPOINT opnieuw uitgevoerd en vervolgens de tabel met geoptimaliseerd geheugen gemaakt.
USE Test; GO DECLARE @var dbo.inMemoryTableType; INSERT INTO @var (id) VALUES (1) SELECT * from @var; GO
Na het bekijken van het logboek, zag ik geen logboekactiviteit. Deze methode is in feite 100% in-memory.
Afhalen
Tabelvariabelen gebruiken tempdb op dezelfde manier als tijdelijke tabellen tempdb gebruiken. Tabelvariabelen zijn geen in-memory constructies, maar kunnen het wel worden als u voor het geheugen geoptimaliseerde, door de gebruiker gedefinieerde tabeltypen gebruikt. Vaak vind ik tijdelijke tabellen een veel betere keuze dan tabelvariabelen. De belangrijkste reden hiervoor is dat tabelvariabelen geen statistieken hebben en, afhankelijk van de versie en instellingen van SQL Server, de rijschattingen uitkomen op 1 rij of 100 rijen. In beide gevallen zijn dit gissingen en worden ze schadelijke stukjes verkeerde informatie in uw query-optimalisatieproces.
Houd er rekening mee dat sommige van deze functieverschillen in de loop van de tijd kunnen veranderen. In recente versies van SQL Server kunt u bijvoorbeeld extra indexen maken voor een tabelvariabele met behulp van inline indexsyntaxis. De volgende tabel heeft drie indexen; de primaire sleutel (standaard geclusterd) en twee niet-geclusterde indexen:
DECLARE @t TABLE ( a int PRIMARY KEY, b int, INDEX x (b, a DESC), INDEX y (b DESC, a) );
Er is een geweldig antwoord op DBA Stack Exchange waar Martin Smith de verschillen tussen tabelvariabelen en #temp-tabellen uitvoerig beschrijft:
- Wat is het verschil tussen een tijdelijke tabel en een tabelvariabele in SQL Server?