Managing TEMPDB Issues
When a TEMPDB disk space alert occurs its typically due to only a one thing, a long running open transaction or process. Currently, due to how our build process creates TEMPDB, both the TEMPDB datafiles and transaction log itself are located on the same dedicated drive (X:\). Due to this, space issues can occur for the following reasons:
One or more TEMPDB data-files auto-grow
This is only an issue when the auto-growth size is very large. Some datafiles will have enough space on disk to grow while others wont be able to. These large autogrowth sizes cause drive to run out of space before all files can grow equally.
Nothing can be done in this scenario outside of fixing the TEMPDB metadata during a service cycle
This can be checked by reviewing the standard reports
Right Click TEMPDB → Reports → Standard Reports → Disk Usage
Look for auto-growths for both Datafiles and LogFiles
The TEMPDB transaction log required more space to grow due to a long running open transaction within TEMPDB itself
The below scripts will help determine if this is true
Due to TEMPDB drive (H:\) being a located on a local drive which cannot be grown, we have to treat TEMPDB uniquely. Please follow the below procedure when TEMPDB space alerts occur.
Run the below scripts on the server having TEMPDB issues
USE tempdb;
GO
IF OBJECT_ID('tempdb..#DiskSpaceMetrics') IS NOT NULL DROP TABLE #DiskSpaceMetrics
SELECT @@ServerName AS ServerName,
DBName,
LogicalFileName,
CASE FileType WHEN 0 THEN 'DATA' ELSE 'LOG' END AS FileType,
FileGroupName,
PhyscialFileName,
CEILING(FileSize) AS FileSizeMB,
SpaceUsed AS SpaceUsedMB,
ROUND((FileSize - SpaceUsed),2) AS SpaceFreeMB,
ROUND(100*((FileSize-SpaceUsed)/FileSize),2) AS PercentFree,
MaxSize AS MaxSizeMB,
FileGrowth AS FileGrowthMB,
IsPercentGrowth,
MountPoint,
DiskSize AS DiskSizeMB,
DiskFreeSpace AS DiskFreeSpaceMB,
ROUND(DiskPercentFree,2) AS DiskPercentFree
INTO #DiskSpaceMetrics
FROM
(
SELECT
db_name() as DBName,
df.name AS [LogicalFileName],
df.type AS FileType,
df.physical_name AS PhyscialFileName,
CAST(df.size/128.0 AS FLOAT) AS [FileSize],
(CAST(CASE df.type WHEN 2 THEN 0 ELSE CAST(FILEPROPERTY(df.name, 'SpaceUsed') AS float)* CONVERT(float,8) END AS float))/1024 AS [SpaceUsed],
CASE
WHEN df.type_desc = 'FILESTREAM' THEN NULL
WHEN df.is_percent_growth = 0
THEN ceiling((df.growth * 8192.0)/(1024*1024))
ELSE df.growth
END AS FileGrowth,
df.is_percent_growth AS IsPercentGrowth,
g.name as [FileGroupName],
CASE df.max_size WHEN -1 then df.max_size else df.max_size/128 end as MaxSize,
v.volume_mount_point AS MountPoint,
CAST((v.total_bytes/1024)/1024 AS FLOAT) AS DiskSize,
CAST((v.available_bytes/1024)/1024 AS FLOAT) AS DiskFreeSpace,
CAST(CAST(v.available_bytes AS FLOAT)/ CAST(v.total_bytes AS FLOAT) AS FLOAT) * 100 AS DiskPercentFree
FROM sys.database_files AS df
INNER JOIN sys.master_files m on df.file_id = m.file_id
LEFT JOIN sys.data_spaces AS g ON df.data_space_id=g.data_space_id
CROSS APPLY sys.dm_os_volume_stats(database_id, m.file_id) v
WHERE m.database_id = DB_ID()
) DBFileSizeInfo
ORDER BY FileType
SELECT Name AS DBName, log_reuse_wait_desc FROM sys.databases WHERE name = DB_NAME(DB_ID())
SELECT ServerName,DBName AS ObjectName,SUM(FileSizeMB) AS TotalSizeMB, SUM(SpaceFreeMB) AS TotalFreeSpaceMB,ROUND(100*((SUM(FileSizeMB)-SUM(SpaceUsedMB))/SUM(FileSizeMB)),2) AS TotalPrecentFree
FROM #DiskSpaceMetrics
WHERE FileType ='DATA'
GROUP BY ServerName,DBName
UNION
SELECT ServerName,DBName+' Log' AS ObjectName,SUM(FileSizeMB) AS TotalSizeMB, SUM(SpaceFreeMB) AS TotalFreeSpaceMB,ROUND(100*((SUM(FileSizeMB)-SUM(SpaceUsedMB))/SUM(FileSizeMB)),2) AS TotalPrecentFree
FROM #DiskSpaceMetrics
WHERE FileType ='LOG'
GROUP BY ServerName,DBName
SELECT DISTINCT MountPoint, DiskSizeMB AS TotalDiskSpace, DiskFreeSpaceMB, DiskPercentFree
FROM #DiskSpaceMetrics;
SELECT ServerName, DBName, LogicalFileName, FileType, PhyscialFileName, FileSizeMB AS TotalSizeMB, PercentFree, MaxSizeMB, FileGrowthMB, IsPercentGrowth
FROM #DiskSpaceMetrics;
The above script will produce 4 distinct outputs
The first will show you whether the transaction log is waiting on anything to truncate
If log_reuse_wait_desc is ACTIVE_TRANSACTION, please look for a long running open transaction
If log_reuse_wait_desc is NOTHING, the transaction log may be shrunk to free up space (ONLY if its determined that log growth is determined to be the culprit)
The second will provide details on total/free space for both TEMPDB and its transaction log
If you see a low TotalPercentFree space on the transaction log but high TotalPrecentFree space for the databases itself, this may mean we have a log running transaction open causing the TEMPDB log to grow. In this situation, you should proceed to determine if the log running open transaction can be killed by reaching out to the code owner
If you see low TotalPercentFree for TEMPDB itself, please run below script to determine what SPID is causing high TEMPDB usage. If this is due to a user query, please reach out to user and determine if it can be stopped or killed
sp_whoisactive @filter_type ='Database', @filter = 'tempdb', @show_sleeping_spids =2
The Third output will show you all LUNs associated with TEMPDBThis will show you how much space is left and if any other LUNs are associated with TEMPDB besides H:\
The last output shows all data file details for TEMPDB
Pay close attention to MaxSizeMB as this will help you understand if an auto-growth could of been the culprit. If the MaxSizeMB is more then the totalSizeMB, then an auto-growth can occur. This may be a problem and should be fixed to avoid future space issues
2. If its determined that transaction log auto-growth is the cause of the TEMPDB drive running out of space, follow below:
Review standard reports for log autogrowths
Review above output for MaxSizeMB of the LOG file. If value is 2097152, this means auto-growth is unlimited
Review the lg_common LUN for freespace
If there is ample free space on the lg_common LUN, we will want to added a log file to that LUN with below script. File has been capped at 200 GB (Make sure this is enough!)
ALTER DATABASE [tempdb] ADD LOG FILE ( NAME = N'templog_01', FILENAME = N'W:\SQL\Logs\<log mountpoint>\templog_01.ldf' , SIZE = 4194304KB , MAXSIZE = 209715200KB , FILEGROWTH = 4194304KB )
Lastly, we will want to attempt to shrink the original TEMPDB log file by some amount. We can shrink the TLOG by 1 of two ways, TRUNCATEONLY, or shrinking it to a determined size. Depending on how much free space the log file has, start with TRUNCATE ONLY.
Make sure to look for blocking when running below script!
USE [tempdb]
GO
DBCC SHRINKFILE (N'templog' , TRUNCATEONLY)
GO
Lastly, we need to cap log file to its current size. This will stop it from growing further and causing another space issue. This can be done using below script:
USE [tempdb]
GO
ALTER DATABASE [tempdb] MODIFY FILE ( NAME = N'templog', MAXSIZE = <SIZE OF LOG FILE IN KB>KB )
GO