There are lots of myths regarding Table variable . You can find lots of theories that Table variable has no impact on transaction log since it is out of scope of transaction. You can find lots of articles that Table variable is stored in memory too. I decided to do some tests to see if Table variable could have impact on transaction log and if it is physically created in tempdb .
Important note at the beginning. Try bellow mentioned queries on your test environment only! Do not run it on production. I used SQL server 2017 installed on my laptop locally. It is better that I could eliminate possible impact of other processes running on SQL Server.
In my sample I created simple Table variable filling with lots of data in while cycle. In another query window I will use undocumented sys.fn_dblog function to read what is happening in transaction log.
I sized transaction log file of temporary table at very low value – 4MB. We will see if insert to Table variable can increase its file size.
Let’s clean up transaction log of temporary table first. Look at script where sys.fn_dblog function is called, to see how the transaction log looks like. There are only three records returned.
CHECKPOINT SELECT * FROM sys.fn_dblog(NULL, NULL)
Execute script with insert rows to Table variable and do it in neverending while cycle, like I do. The main issue was to have query still running while getting data from log. Since the query was stopped, I was not able to get needed data from the log function. So it is important that the query with table variable you would like to analyze will be still running while getting data from transaction log in another query window.
SELECT [Transaction Name], [spid], [Xact ID], f.[Page ID], f.[parent transaction id], [Transaction ID],[Transaction Name] ,AllocUnitName,* FROM sys.fn_dblog(NULL,NULL) f WHERE [SPID]=56
Get SPID of inserting query and run above mentioned query in new query window with SPID you get. In output you can see name of Temporary table we created as name of transaction. We are lookingn for Transaction Name wiht AllocPages.
Take Parent Transaction ID from the row where column Transaction Name = AllocPages and change predicate to select records base on Transaction ID.
SELECT [Transaction Name], [spid], [Xact ID], f.[Page ID], f.[parent transaction id], [Transaction ID],[Transaction Name] ,AllocUnitName,* FROM sys.fn_dblog(NULL,NULL) f WHERE [Transaction ID]='0000:00002622'
Here we can see temporary table name in Allocation unit name column. The name of Allocation unit uses the same convention like for local temporary table. It really seems that Table variable is physically created in tempdb as Temporary table.
Another view could be made with Allocation units, where you can check how many pages were used in our transaction in Table variable.
SELECT so.name, so.object_id, sp.index_id, sp.partition_id, sp.hobt_id, sa.allocation_unit_id, sa.type_desc, sa.total_pages FROM sys.objects so JOIN sys.partitions sp on so.object_id = sp.object_id JOIN sys.allocation_units sa on sa.container_id = sp.hobt_id
Now we verify that the temporary table is connected to our Table variable and if so, that the data are stored in tempdb. We check that data inserting to Table variable can be found in pages of tempdb data files. I took first Page ID from row with Operation of LOP_MODIFY_ROW type. It is highlighted on picture 05 – 0005:0000bd90. First number 0005 corresponds to tempdb file ID, the second number converted from hex to dec 48528 is page ID. Use DBCC command bellow to get SGAM page to get info where pages with data are placed.
DBCC PAGE(2,5, 48528 , 3) WITH TABLERESULTS;
We put 2 as first parameter meaning tempdb database ID. The second parameter 5 is database file ID, 48528 number of page, and last parameter 3 output style. Bellow we get list of ranges where pages are allocated.
Let’s choose one page from above listed allocated pages range- highlighted. I choose page 48537 using DBCC command again.
DBCC PAGE(2,5, 48537 , 3) WITH TABLERESULTS;
Look at details from DBCC output bellow. At Field column we can find id, testdata column name defined in our Table variable. In VALUES column get data already inserted.
We verified that Temporary table dbo.#BC836344 is Table variable we declared in our testing query. Now look at transaction log size. We see that tempdb log file size increased.
When stopped the query inserting data to table variable we can see that the temporary table disappeared from Transaction log.
Finally we checked that
- Table variable is actually temporary table created in tempdb , persisted during query run.
- we could get inserted data by accessing pages from tempdb
- DML operation on Table variable have impact on transaction log of tempdb
- It can even cause unexpected increase of transaction log size
What is not still clear to me, or maybe I dont see it, why it is implemented this way. Table variable is defined like out of transaction scope table by Microsoft. Why there is a need to write data to transaction log, it seems useless to me.
With this post I proved that Table variable is actually Temporary table, created in tempdb with some specific behavior. Next time could be insteresting to compare above mentioned sample with local Temporary table to see the differences in transaction log and pages allocation. Stay tuned.