Tempdb Space Usage in SQL Server

We all know how important tempdb is and know that tempdb gets recreated every time SQL Server is restarted. We place tempdb on a fast disk array exclusively hoping it will run as fast as possible. Here we dig a little deeper to focus on how space is being used inside tempdb.

Space Usage categories

Roughly, we can separate tempdb usage into three categories:

  • User object
  • Internal job
  • Version store

I would like to focus our discussion on few of the common operational tasks that utilize tempdb.

User Objects

Any user with permission to connect to the SQL instance can create a temporary table and table variables. You can’t back up or restore tempdb, so any temporary object or table variable created previously (before SQL Server was restarted) will be wiped out and cannot be recovered.

The scope of user objects are either in the user session or in the routine. Routine can be in the form of a stored procedure, function or trigger. User objects in tempdb can be like one of the list below:

  • User table and index (created explicitly in tempdb)
  • Global temporary table and index
  • Local temporary table and index
  • Table variable

There are two ways you can query to get the space used by tempdb user objects.

select convert(numeric(10,2),round(sum(data_pages)*8/1024.,2)) as user_object_reserved_MB

from tempdb.sys.allocation_units a

inner join tempdb.sys.partitions b on a.container_id = b.partition_id

inner join tempdb.sys.objects c on b.object_id = c.object_id

Returned result:



reserved_MB= convert(numeric(10,2),round((unallocated_extent_page_count+version_store_reserved_page_count+user_object_reserved_page_count+internal_object_reserved_page_count+mixed_extent_page_count)*8/1024.,2)) ,

unallocated_extent_MB =convert(numeric(10,2),round(unallocated_extent_page_count*8/1024.,2)),


user_object_reserved_MB =convert(numeric(10,2),round(user_object_reserved_page_count*8/1024.,2))

from sys.dm_db_file_space_usage


Returned result:

Note that the returned value for [user_object_reserved_MB] from both queries is almost the same.

Internal objects

There are three types of objects considered to be internal objects.

  1. Work tables
    • Spooling, to hold intermediate results during a large query
    • Temporary large object storage (LOB)
    • Processing SQL Service Broker Objects
    • Common table expression
    • Keyset-driven and static cursors
  2. Work files
    • Hash join or hash aggregate operations
  3. Sort units
    • ORDER BY, GROUP BY, UNION queries
    • Index rebuilt or creation (with sort in tempdb is specified)

Unfortunately, there is no catalog view or dynamic management object that can provide the detailed page count information for each internal object. You can get the total number of pages in tempdb allocated for internal objects from DMV — sys.dm_db_file_space_usage.


reserved_MB=(unallocated_extent_page_count+version_store_reserved_page_count+user_object_reserved_page_count+internal_object_reserved_page_count+mixed_extent_page_count)*8/1024. ,

unallocated_extent_MB =unallocated_extent_page_count*8/1024.,


internal_object_reserved_MB =internal_object_reserved_page_count*8/1024.

from sys.dm_db_file_space_usage

Returned result for internal object space used in tempdb:

Version Store

Version store is a collection of data pages that holds the data rows used for row versioning. Below are the features that use version store:

  • Triggers
  • MARS
  • Online Index operation
  • Row versioning-based transaction isolation level
    • Read-committed isolation level (statement-level read consistency)
    • Snapshot isolation level (transaction-level read consistency)

For read-committed isolation level, version store only needs to keep the row version until the end of the select statement.

For snapshot isolation level, version store will need to keep the version of the row when the transaction started so the transaction can refer back the original version of the row. If the transaction happens to be unreasonably long, with many rows modified by some other transactions, the snapshot query may fail if tempdb has space shortage and version store can no longer retain all the version required.

There are performance counters that can be used to monitor the size of tempdb and version store.

SQLServer: Transactions performance object

SQL Server transactions performance object

Object counter Description Free Space in tempdb Free space in kilobytes for tempdb Version store size in KB, tempdb being used to store snapshot isolation level row versions Version generation rate row versions are added to tempdb version store (Kilobyte/sec) Longest Transaction Running Time The length of time (in seconds) since the start of the transaction that has been active longer than any other current transaction. Snapshot Transactions The number of currently active transactions using the snapshot isolation level.

You can also query dynamic management view — sys.dm_db_file_space_usage — to get the total number of pages currently allocated in tempdb for versions tore.

reserved_MB=(unallocated_extent_page_count+version_store_reserved_page_count+user_object_reserved_page_count+internal_object_reserved_page_count+mixed_extent_page_count)*8/1024. ,
unallocated_extent_MB =unallocated_extent_page_count*8/1024.,
version_store_reserved_MB =version_store_reserved_page_count*8/1024.
from sys.dm_db_file_space_usage

Returned result for version stored occupant space on tempdb:

SQL Server dynamic management view

Now let’s look into some features that use tempdb and how to estimate the space required on tempdb for performing these operations.


For DBCC CHECKDB, we can use DBCC CHECKDB WITH ESTIMATEONLY to check how much space it requires without actually executing the command. It returns resultset for [Estimated TEMPDB space needed for CHECKALLOC(KB)] and [Estimated TEMPDB space needed for CHECKTABLES(KB)].

You may want to run this estimation for a very large database and ensure your tempdb has sufficient space to complete the task.

Index Creation and Rebuild

Tempdb space is only needed if SORT_IN_TEMPDB is on. The tempdb space is needed to store the intermediate sort result for index building. Let’s take a look at both online index operation and offline index operation.

Important note; you cannot use SORT_IN_TEMPDB when dropping an index.

1. Offline Index operation and SORT_IN_TEMPDB

Here are examples for how much space we need on tempdb when creating/building index offline with the sort in tempdb option.

Create Non-clustered index:
tempdb should be big enough to store leaf rows of the indexes

index leaf row size * number of rows 

Create Clustered index:
tempdb should be big enough to store data rows of the table.

table row size * number of rows

Clustered and non-clustered indexes from same table:
tempdb should be big enough to carry largest index, usually clustered index is largest among all indexes from one table.

Largest index row size * number of rows

If rebuilding clustered index with different cluster key columns:
Since new clustered index leaf row size and old clustered index leaf row size are identical, so it’s basically the total data rows size of the table

clustered index row size * number of rows

If there are cases when SQL optimizer doesn’t do any sorting or if the sorting area can be performed in memory, then SORT_IN_TEMPDB will be ignored and no space will be needed in tempdb.

2. Online Clustered Index Operation and SORT_IN_TEMPDB

When performing an online index operation for a clustered index, a temporary mapping index is created to fulfill the operation. Below is the formula for calculating a temporary mapping index.

Temporary mapping index size = (number of rows of the table) * (old key size + new index key size - overlapping index key size) / (fillfactor in percentage)

If there are key columns overlapping on the index between the old index key and new index key, then then we need to subtract the overlapping key size.

Create Clustered Index online on a heap table:
tempdb should be big enough to store data rows of the table and temporary mapping index

Data rows of the table= Table row size * number of rows

Temporary mapping index size = (number of rows of the table) * (RID+ new index key size) / (fillfactor in percentage)

Total space = Data rows of the table + Temporary mapping index

Rebuilding Clustered index with different clustered key columns:
tempdb should be big enough to store data rows of the table and temporary mapping index


Data rows of the table = Table row size * number of rows 

Temporary mapping index size = (number of rows of the table) * (old index key size+ new index key size - size in overlapping) / (fillfactor in percentage)

The total tempdb space needed = Data rows of the table + Temporary mapping index


It’s imperative to understand how SQL Server uses tempdb so we can do better perform capacity planning when setting up tempdb. A proper sizing and configured tempdb can improve the overall performance of a SQL instance.

See all articles by Claire Hsu

Claire Hsu
Claire Hsu
Claire Hsu has nearly 10 years' experience in database administration, architecture, engineering and development, ranging from SQL 7.0, 2000, 2005 and 2008 environments. Currently, she is a senior DBA for a global infrastructure team in an investment management firm located in New York City. She is certified in MCP, OCP 10G, MCTS and MCITP on SQL Server 2005, and has a master's in Electrical Engineering from University of Massachusetts, Amherst. Her focus as DBA includes project management, handling critical projects like server upgrades, migration, high availability features deployment, performance tuning, monitoring, ensuring business continuity, and client facing and engineering automated processes.

Get the Free Newsletter!

Subscribe to Cloud Insider for top news, trends & analysis

Latest Articles