Faster INSERTs in Tempdb – Optimized/Minimal Tempdb Logging

This blog post first appeared on SQLMaestros

In this blog post, we will see how SQL Server optimises Tempdb logging for faster CRUD operations. For the purpose of this tutorial, we will perform the same operations in a regular user database versus Tempdb, and note down execution time (performance comparison).

Thanks to Hugo Kornelis, Thomas Grohser, Uwe Ricken, Simon Sabin & Pam Lahoud who answered my questions helping me demystify this.

Let’s create a test table in user database (AdventureWorks2016) and perform an INSERT of 10000 records in a loop.

-- change database context
use AdventureWorks2016
GO

-- Create table testtable
IF OBJECT_ID('dbo.testtable', 'U') IS NOT NULL DROP TABLE dbo.testtable;
GO

-- creating a table
-- 1 record per page (just for the test)
create table testtable
(name char(8000) default 'Hi')

-- Insert 10000 records (note: this is user database)
-- note the total execution time
SET NOCOUNT ON;
declare @cnt int = 0
while @cnt<10000
begin
INSERT INTO dbo.testtable DEFAULT VALUES;
set @cnt=@cnt+1
end
GO

-- Total execution time in user database?

The total execution time of INSERT loop on my slow VM is 8 seconds. Your’s may be a bit faster 🙂

Now let’s do the same in Tempdb.

-- Lets do the same in Tempdb database
-- change database context
use tempdb
GO

-- Create table testtable
IF OBJECT_ID('dbo.testtable', 'U') IS NOT NULL DROP TABLE dbo.testtable;
GO

-- creating a table
-- 1 record per page (just for the test)
create table testtable
(name char(8000) default 'Hi')

-- Insert 10000 records (note: this is Tempdb database)
-- note the total execution time
SET NOCOUNT ON;
declare @cnt int = 0
while @cnt<10000
begin
INSERT INTO dbo.testtable DEFAULT VALUES;
set @cnt=@cnt+1
end
GO

-- Total execution time in Tempdb?

In Tempdb, the INSERT operation takes less than 1 second. 8 seconds vs less than a second -That is quite a difference.

This happens because of minimal logging in Tempdb. In other words, Optimized Tempdb logging. SQL Server generates far less log bytes for Tempdb log file because unlike a user database, Tempdb only has take care of UNDO, not REDO. Tempdb  is a throwaway database. In case of crash recovery, SQL Server has to perform UNDO & REDO for a user database. But for Tempdb, since it is always recreated on instance start, there is no redo information needed.

Let’s explore the internals.

We will recreate the tables and just insert one record and check the log records.

-- Lets explore some internals
-- This time let's insert only 1 record

-- change database context to user database
use AdventureWorks2016
GO

-- DROP testtable
DROP TABLE dbo.testtable;
GO

-- creating the table again
create table testtable
(name char(8000) default 'Hi')
GO

-- clean starting point
checkpoint
GO

-- Insert 1 record
INSERT INTO dbo.testtable DEFAULT VALUES;
GO

-- Lets do the same in Tempdb
-- change database context to Temdb

use tempdb
GO

-- DROP testtable
DROP TABLE dbo.testtable;
GO

-- creating the table again
create table testtable
(name char(8000) default 'Hi')
GO

-- clean starting point
checkpoint
GO

-- Insert 1 record
INSERT INTO dbo.testtable DEFAULT VALUES;

Now let’s check the log records for both the databases.

   
-- Lets compare the Log Records
-- run from Start to finish as a single batch
--Start
use AdventureWorks2016
GO

select Operation, [Log Record Fixed Length], [Log Record Length], [RowLog Contents 0], [RowLog Contents 1], [RowLog Contents 2], [RowLog Contents 3], [RowLog Contents 4], [RowLog Contents 5] from fn_dblog (NULL, NULL)
where Operation = 'LOP_INSERT_ROWS'

use tempdb
GO

select Operation, [Log Record Fixed Length], [Log Record Length], [RowLog Contents 0], [RowLog Contents 1], [RowLog Contents 2], [RowLog Contents 3], [RowLog Contents 4], [RowLog Contents 5] from fn_dblog (NULL, NULL)
where Operation = 'LOP_INSERT_ROWS'
--FInish

-- Observe: The differences in columns Log Record Length, RowLog Contents 0 & RowLog Contents 2

So, the key thing to observe is the Log Record Length. 8100 bytes versus 72 bytes. Why 8100 bytes? Well, remember our table definition? We had a fixed length character column ‘name’ 8000 bytes.

You can also compare the content in RowLog Contents 0 and 2 between user database and Tempdb.

This was an INSERT example. What will be the UNDO of an INSERT? Well ‘no existence’. If this was an update operation then SQL Server has to store the before image and after image of the record, and numbers would have been different.

Let’s do an update of this record and observe a few more internals.

-- Now, let's do an update on both the tables (databases)

-- First, user database update

use AdventureWorks2016
go

checkpoint
GO

-- update 1 record
update testtable
set name = 'www.DPS10.com'


-- Next Tempdb database update

use tempdb
go

checkpoint
GO

-- update 1 record
update testtable
set name = 'www.DPS10.com'

Now, lets compare the log records again. This time, we are filtering on ‘LOP_MODIFY_ROW’.

-- Lets compare the Log Records
-- run from Start to finish as a single batch
--Start
use AdventureWorks2016
GO

select Operation, [Log Record Fixed Length], [Log Record Length], [RowLog Contents 0], [RowLog Contents 1], [RowLog Contents 2], [RowLog Contents 3], [RowLog Contents 4], [RowLog Contents 5] from fn_dblog (NULL, NULL)
where Operation = 'LOP_MODIFY_ROW'

use tempdb
GO

select Operation, [Log Record Fixed Length], [Log Record Length], [RowLog Contents 0], [RowLog Contents 1], [RowLog Contents 2], [RowLog Contents 3], [RowLog Contents 4], [RowLog Contents 5] from fn_dblog (NULL, NULL)
where Operation = 'LOP_MODIFY_ROW'
--FInish

-- Observe: The differences in columns Log Record Length, RowLog Contents

This time the difference in bytes is quite less. The update is only for 13 characters (https://www.DPS10.com) (26 bytes) + some overhead.

Also note the undo content for Tempdb now in RowLog Contents 0.

You can try a few more things. Eg; increase the length of the character data and fire an update and observe the difference. Perform a delete and observe the difference, so on.

Pro Tip #1: Yes, use Tempdb for all temporary data, ETL, etc.
Pro Tip #2: The age old best practice – focus on the choice of data types !

Next, I will be covering some stuff on Eager Writes.

Thanks for reading. If you liked the content, do share it. I am on Twitter if you wish to connect: https://www.twitter.com/A_Bansal
You can also subscribe to my exclusive newsletter ConnectWithAB – https://sqlmaestros.com/stay-connected-with-amitbansal/

   

About Amit Bansal

Amit Bansal is always brainstorming around SQL Server. Despite working with SQL since 1997, he is amazed that he keeps learning new things every single day. SQL Server is AB's first love, and his wife does not mind that. He tries to share as much and spreads the SQL goodness. Internals and Performance Tuning excites him, and also gives him sleepless nights at times, simply because he is not a genius, but quite a hard worker and does not give up. It has been a long and exciting journey since 1997, you can read here: http://sqlmaestros.com/amit-bansal/ He is on Twitter: https://www.twitter.com/A_Bansal

View all posts by Amit Bansal →

Leave a Reply

Your email address will not be published.