Showing posts with label Performance tuning. Show all posts
Showing posts with label Performance tuning. Show all posts

April 30, 2025

Troubleshooting TempDB Growth in SQL Server

 



Why TempDB Grows and Doesn’t Reset Easily

TempDB Usage Causes: TempDB is a global workspace for SQL Server, used for sorting, hashing, temporary tables, table variables, versioning (snapshot isolation or read-committed snapshot), and many internal If a query requires more memory than the server has allocated (for example, a misestimated join or sort), it will spill to TempDB, writing work tables to disk. Large temporary tables or result sets can also consume significant TempDB space. All these factors can cause TempDB to grow rapidly during heavy queries or long transactions.

Continuous Growth: In this case, a long-running linked server query likely caused internal work tables (spools, hash join overflow, sort runs) in TempDB, which kept allocating pages. TempDB will continue to grow until the operation finishes or TempDB runs out of disk. If nothing intervenes, the TempDB data files remain at the high-water mark size even after the query completes (though the space inside may become free).

No Auto-Shrink by Default: TempDB does not automatically shrink on its own. The only time TempDB’s size resets is at SQL Server startup, when it recreates TempDB from the model database. However, it uses the last configured size (which includes any growths that occurred) as the new initial In our scenario, after the first growth event, TempDB’s files were permanently larger. So even after a restart, TempDB started at that large size – it did not revert to the original smaller size. The space can be reclaimed only by explicitly shrinking the TempDB files or by altering the database file sizes.

Why TempDB Didn’t Shrink on Restart: As explained by Microsoft, when SQL Server restarts, “tempdb is re-created ... and reset to its last configured size The configured size is the last explicit size that was set by a file size changing operation (ALTER DATABASE ... MODIFY FILE or DBCC SHRINKFILE/SHRINKDATABASE)”. In practice, this means any auto-growth or manual growth persists. In our case, TempDB had grown to accommodate the large query, so on restart it was created at that same large size. Only after manually shrinking or altering TempDB would subsequent restarts use a smaller size.

Space Not Freed During Operation: During the long query, attempts to shrink TempDB would likely fail (as the question scenario suggests) because the work tables or allocations were still active. The error about a “worktable on hold” indicates TempDB space was tied up by an active operation, blocking shrinking. Thus, the DBA had to restart SQL Server to break free of the operation and then shrink TempDB to reclaim space

In summary, TempDB grew large because of an expensive operation and stayed large because SQL Server preserved that size setting. This is normal behavior. The key is to identify what caused the growth (the linked server query, in this case) and address that root cause rather than relying on restarts or shrinks.

Common Factors causing TempDB Growth




1.        Large Sort Operations

o    Queries with ORDER BY clauses on large result sets

o    Group By operations requiring intermediate sorting

o    Join operations on non-indexed columns requiring sort operations

2.      Hash Operations

o    Hash joins on large tables

o    Hash aggregates for GROUP BY without appropriate indexes

o    Hash spills to disk when memory grant is insufficient

3.      Row Versioning

o    Transactions using READ_COMMITTED_SNAPSHOT or SNAPSHOT isolation levels

o    Long-running transactions preventing version cleanup

o    Heavy DDL operations under versioning isolation levels

4.      Table Variables and Temporary Tables

o    Extensive use of table variables or #temp tables

o    CTEs that materialize large result sets

o    Nested temporary tables in stored procedures

5.      Index Operations

o    Creating or rebuilding indexes on large tables

o    Statistics updates on large tables

o    Online index operations

6.      DBCC Operations

o    DBCC CHECKDB and similar maintenance tasks

o    Index defragmentation operations

7.       Parallelism

o    Parallel execution plans for complex queries

o    High MAXDOP settings forcing parallel operations

8.      Query Spills

o    Memory grant underestimation causing operations to spill to TempDB

o    Memory pressure forcing in-memory operations to disk

9.      LOB Data Operations

o    Operations on large BLOB/TEXT/XML columns

o    Intermediate storage of large LOB data

10.    Excessive Workspace Memory Usage

o    Window functions on large datasets

o    Recursive CTEs with many iterations

o    Complex analytical functions

11.      Linked Server/Distributed Queries

o    When you use a four-part name in a query (e.g. SELECT ... FROM LocalTable JOIN LinkedServer.RemoteDB.dbo.Table ...), SQL Server’s optimizer may decide to copy entire remote tables into the local TempDB[1] for processing.

o    A linked server query ended up scanning a large remote table and sending millions of rows across the network one by one, ultimately copying the entire table. This kind of behavior would consume enormous TempDB space for intermediate storage (e.g. sorting or hashing that data).


Step-by-Step Troubleshooting TempDB growth Guide

     Monitor TempDB Space: First, confirm that TempDB is indeed the database consuming the space. You can run sp_spaceused in TempDB or query the DMV sys.dm_db_file_space_usage to see space used by TempDB. For example, SELECT (SUM(user_object_reserved_page_count) + SUM(internal_object_reserved_page_count))*8/1024 AS Tempdb_MB_Used FROM sys.dm_db_file_space_usage;. This will show how many MB are in use. If TempDB is nearly full or unusually large, it’s a red flag.

     Check for Recent Growth Events: Look at the SQL Server log (or Extended Events if configured) for any messages about TempDB file auto-growth. An auto-growth event will indicate when and how much TempDB expanded. This can correlate with the timing of a query. Also check Windows event logs or alerts if any were triggered for low disk space on the TempDB drive.

     Identify Sessions Using TempDB Heavily:Use dynamic management views to find which session is consuming TempDB space. Two useful DMVs are sys.dm_db_session_space_usage and sys.dm_db_task_space_usage. These can tell you how many pages each session has allocated in TempDB (both user and internal objects). For example, a query like:

SELECT

    s.session_id,

    r.status,

    (t.internal_objects_alloc_page_count + t.user_objects_alloc_page_count) AS pages_used,

    DB_NAME(r.database_id) AS database_context,

    r.command, r.sql_text

FROM sys.dm_db_task_space_usage AS t

JOIN sys.dm_exec_requests AS r

    ON t.session_id = r.session_id AND t.request_id = r.request_id

CROSS APPLY sys.dm_exec_sql_text(r.sql_handle) AS sql_text

JOIN sys.dm_exec_sessions AS s ON t.session_id = s.session_id

WHERE (t.internal_objects_alloc_page_count + t.user_objects_alloc_page_count) > 0

ORDER BY pages_used DESC;

     Alternatively, you can use community tools like sp_WhoIsActive (by Adam Machanic) which, when run with appropriate parameters, will list TempDB usage per session. For example, EXEC sp_WhoIsActive @get_tempdb_info=1; will include TempDB allocation for each active query.

Take Emergency Action (If Needed):
 If the system is at risk of crashing due to no space (TempDB or log completely full), you need to free resources by Killing the Offending Session

After the session is gone, TempDB will still be at its grown size (files won’t shrink automatically),you can attempt a manual shrink of TempDB:
USE tempdb;

DBCC SHRINKFILE('tempdev', <desired_size_mb>);

Keep in mind shrinking TempDB is typically a last resort and may cause fragmentation; it’s usually better to leave it if you have the disk space, and adjust the initial size for next startup.

TempDB Configuration Best Practices




Proper TempDB configuration can alleviate some issues and prevent TempDB from becoming a bottleneck or single point of contention:

     Multiple Data Files: It’s a best practice to use multiple TempDB data files to reduce allocation contention on system pages (PFS, GAM, SGAM). The latest Microsoft guidance suggests one TempDB data file per logical CPU, up to 8 files For example, if your server has 16 cores, start with 8 TempDB files; if it has 4 cores, use 4 files. Having 8 equally sized files often suffices for most workloads . Only add more than 8 if you still observe contention (manifested by PAGELATCH_UP/EX waits on TempDB pages)

     Preallocate Adequate Size: Configure the initial size of TempDB data files to accommodate typical usage peaks. This avoids frequent auto-growths, which can be expensive. For example, if TempDB tends to use up to 20 GB during heavy operations, set the total initial size of files to 20 GB (spread across files, e.g., 8 files of 2.5 GB each) to start with. This way, SQL Server doesn’t have to pause to grow the files during a heavy query.

     Autogrowth Settings: Set TempDB files to auto-grow in reasonable chunks (not too small, not too large). Avoid percentage growth settings, as they become inefficient (10% of a 20 GB file is 2 GB, which might be fine, but 10% of a 100 GB file is 10 GB which might be too large a jump and take long to allocate). A fixed growth size of a few hundred MB to a couple GB is typically recommended.

     Uniform Size and Growth: Ensure all TempDB data files are the same size and have the same growth settings. SQL Server uses a proportional fill algorithm for TempDB files, and if one file is smaller, it can become a hotspot. Monitor after any auto-growth that all files remain equal – if one file grew, manually grow the others to match if needed.

     TempDB on Fast Storage: Place TempDB on one of the fastest storage volumes available, separate from critical user databases. TempDB is highly I/O intensive for many workloads, so using SSD/NVMe storage for it can significantly improve performance. This doesn’t prevent growth issues per se, but it makes TempDB operations faster and more resilient.

     TempDB Logging: TempDB has its own log file. Usually one log file is enough (don’t create multiple log files – that doesn’t improve throughput). But do set the TempDB log’s initial size and autogrowth appropriately as well. As noted in one best practice guide, configure TempDB’s log with a large initial size so that on restart it doesn’t start tiny and then have to grow.

     Regular Maintenance: You generally should not need to shrink TempDB on a schedule. Instead, set it up correctly and let it be. If you encounter an unexpected growth (as in this scenario), afterwards you might shrink it back to normal size during a maintenance window. But avoid setting TempDB to auto-shrink or frequently shrinking it, as that can interfere with performance and will likely just grow again.

Monitoring and Alerting for TempDB Growth

     SQL Server Agent Alerts: Leverage SQL Server’s built-in alerting mechanism. You can configure an alert on specific error numbers:

     Alert on Error 1105 (TempDB filegroup full)

sp_add_alert @name='TempDB Full', @message_id=1105, @severity=17, @delay_between_responses=0, @notification_message='TempDB full - investigate session using TempDB'

 

     You can also set up a performance condition alert. For example, an alert when TempDB data file usage > 80% for over 5 minutes. There is a performance counter Free Space in Tempdb (KB) or you can use a custom condition via a job

     Continuous Monitoring of TempDB usage: Consider implementing a job that regularly checks TempDB usage and logs the top consumers.

 

     OS Level Monitoring: Don’t forget to monitor disk space at the OS level. Ensure your infrastructure monitoring checks the drive where TempDB resides and the drive for log files. If free space drops below a threshold (say 15%), alerts should go out. In our scenario, an alert on the disk filling up might have been a final warning before things went completely south.

 



January 10, 2024

MS SQL Query Store usage scenarios

 The Query Store feature provides you with insight on query plan choice and performance for SQL Server, Azure SQL Database, Azure SQL Managed Instance, and Azure Synapse Analytics. The Query Store simplifies performance troubleshooting by helping you quickly find performance differences caused by query plan changes. Query Store automatically captures a history of queries, plans, and runtime statistics, and retains these for your review. It separates data by time windows so you can see database usage patterns and understand when query plan changes happened on the server. 


Query Store can be used in wide set of scenarios when tracking and ensuring predictable workload performance is critical. Here are some examples you can consider:


  • Quickly find and fix a plan performance regression by forcing the previous query plan. Fix queries that have recently regressed in performance due to execution plan changes.

  • Determine the number of times a query was executed in a given time window, assisting a DBA in troubleshooting performance resource problems.

  • Identify top n queries (by execution time, memory consumption, etc.) in the past x hours.

  • Audit the history of query plans for a given query.

  • Analyze the resource (CPU, I/O, and Memory) usage patterns for a particular database.

  • Identify top n queries that are waiting on resources.

  • Understand wait nature for a particular query or plan.

January 27, 2016

Interesting Facts About Database Indexes

Interesting Facts About Database Indexes
  • Create Clustered Indexes on the tables’ Natural Keys. Natural Keys, are the fields that best identify the row’s data. For example, the Primary Key used for a table might be a Unique Identifier or a Big Int, but I might access data through a combination of columns. For a car these columns could be Year, Make, Model and VIN. When you create the Clustered Index, order the columns by their selectivity and use this same order when you query for the information.
  • Create Non-Clustered Indexes on your Primary Keys
  • Create Non-Clustered Indexes for all Foreign Keys
  • Create Non-Clustered Indexes for columns that are used in WHERE, ORDER BY, MERGE, JOIN and other clauses that require matching data.
  • Create Filtered INDEXES to create highly selective sets of keys for columns that may not have a good selectivity otherwise.
  • Use Covering INDEXEs to reduce the number of bookmark lookups required to gather data that is not present in the other INDEXES.
  • Covering INDEXES can be used to physically maintain the data in the same order as is required by the queries’ result sets reducing the need for SORT operations.
  • Covering INDEXES have an increased maintenance cost, therefore you must see if performance gain justifies the extra maintenance cost.
  • If a CLUSTERED INDEX is present on the table, then NONCLUSTERED INDEXES will use its key instead of the table ROW ID.
  • To reduce the size consumed by the NONCLUSTERED INDEXES it’s imperative that the CLUSTERED INDEX KEY is kept as narrow as possible.
  • Physical reorganization of the CLUSTERED INDEX does not physically reorder NONCLUSTERED INDEXES.
  • SQL Database can JOIN and INTERSECT INDEXES in order to satisfy a query without having to read data directly from the table.
  • Favor many narrow NONCLUSTERED INDEXES that can be combined or used independently over wide INDEXES that can be hard to maintain.
  • NONCLUSTERED INDEXES can reduce blocking by having SQL Database read from NONCLUSTERED INDEX data pages instead of the actual tables.

August 12, 2014

What is nested loops join?

What is nested loops join?

The nested loops join uses one join input as the outer input table (shown as the top input in the graphical execution plan) and one as the inner (bottom) input table. The outer loop consumes the outer input table row by row. The inner loop, executed for each outer row, searches for matching rows in the inner input table.
In the simplest case, the search scans an entire table or index; this is called a naive nested loops join. If the search exploits an index, it is called an index nested loops join. If the index is built as part of the query plan (and destroyed upon completion of the query), it is called a temporary index nested loops join. All these variants are considered by the query optimizer.
A nested loops join is particularly effective if the outer input is small and the inner input is preindexed and large. In many small transactions, such as those affecting only a small set of rows, index nested loops joins are superior to both merge joins and hash joins. In large queries, however, nested loops joins are often not the optimal choice.

SELECT * FROM customer, orders 
WHERE customer.customer_num=orders.customer_num 
AND order_date>"01/01/1997";
 

December 24, 2011

MySQL database optimization

1.One of the first places to look to improve performance is queries, particularly the ones that run often.
2.Big gains can be achieved by analyzing these queries and rewriting them efficiently. You can use MySQL’s SHOW QUERY LOG to get an idea of which queries need to be fine tuned.
3.If optimization of your queries s a first goal, the first thing to do is to try implementing indexes. If you have a column involved in searching ( where clause), grouping ( group by clause) or sorting(Order by clause) and columns used in JOIN operations, it is likely result in a performance gain if you create index on these columns.
4.Another factor in creating index is cardinality( i.e.number of unique values),the higher the cardinality, the greater the chance that MySQL uses the index in queries.
5.Index speeds up SELECT queries but slows DELETE,INSERT and UPDTE queries, so create indexes on those columns which are mostly used in SELECT queries.
6.Create scheduled job to REBUILD INDEXES.
7.If business operations doesn’t affect, schedule to RESTART server weekly once when no users are connected to system.
8.Run ANALYZE TABLE command frequently ( schedule it weekly)
9.Run OPTIMIZE TABLE command frequently ( schedule it weekly)
10.SCHEMA OPTIMIZATION: Optimize data types and use DeNormalization if required.
11.Design your tables to minimize their space on the disk. This can result in huge improvements by reducing the amount of data written to and read from disk. Smaller tables normally require less main memory while their contents are being actively processed during query execution. Any space reduction for table data also results in smaller indexes that can be processed faster.
12.If your application makes several database requests to perform related updates, combining the statements into a stored PROCEDURE can help performance. Similarly, if your application computes a single result based on several column values or large volumes of data, combining the computation into a UDF (user-defined function) can help performance.
13.Disk seeks are a huge performance bottleneck. This problem becomes more apparent when the amount of data starts to grow so large that effective caching becomes impossible. If you find this issue then Increase the number of available disk spindles (and thereby reduce the seek overhead) by either symlinking files to different disks or striping the disks.
14.Check if you need partitioning of tables either ROW BASED PARTITIONING or HORIZONTAL PARTITIONING.

For more information, pl use following links.
http://dev.mysql.com/doc/refman/5.5/en/optimization.html
http://docs.oracle.com/cd/E17952_01/refman-5.5-en/mysql-tips.html

Stop Memorizing SQL Part 3 : A Practical SQL Cheat Sheet for Beginners

 A Practical SQL Cheat Sheet for Beginners When learning SQL, students often struggle to remember the correct syntax during exams or practic...