Quickly Find Your Worst-Performing T-SQL Statements

Stored procedure lets you avoid the hassles associated with writing DMV and DMF queries on the fly

Downloads
100201.zip

SQL Server 2008 and SQL Server 2005 include dynamic management views (DMVs) and dynamic management functions (DMFs) that provide performance-related information. However, the most useful information is obtained when you combine results from various DMVs and DMFs. For example, you can combine their results to identify T-SQL statements that are using an excessive amount of server resources.

When you want to quickly identify resourceintensive T-SQL statements, you don’t want to have to wade through DMV and DMF syntax documentation or search for information on how to perform JOIN operations. To avoid the hassles associated with writing DMV and DMF queries on the fly, I wrote a parameter-driven stored procedure named usp_Worst_TSQL. To download usp_Worst_TSQL, click the 100201.zip hotlink at the top of this page.

The usp_Worst_TSQL stored procedure executes three DMVs (sys.dm_exec_query_stats, sys.dm_exec_ cached_plans, and sys.dm_exec_sql_text) and one DMF (sys.dm_exec_plan_attributes), then joins and manipulates the DMV and DMF results to provide a variety of statistics. Table 1, shows some of the available statistics. (The 100201.zip file contains the entire list in the file StatisticsReturned.xls.) With these statistics, you can identify the worst-performing T-SQL statements.

How to Use usp_Worst_TSQL


The usp_Worst_TSQL stored procedure has three optional parameters—@DBNAME, @COUNT, and @ORDERBY—that let you restrict and sort the stored procedure’s output. The @DBNAME parameter lets you retrieve T-SQL statements for a single database. If you don’t include this parameter, the stored procedure returns the statements for all the databases on the server.

The @COUNT parameter limits the number of rows (i.e., T-SQL statements) returned by usp_ Worst_TSQL. If you use this parameter, the stored procedure returns only the top x rows (where x is equal to the @COUNT value). If you don’t use this parameter, the stored procedure returns all rows.

The @ORDERBY parameter identifies the statistic to sort the rows by. Table 1 shows some of the values you can use with this parameter. No matter which statistic you choose, the rows are sorted in descending order. If you don’t include the @ORDERBY parameter, the stored procedure sorts by average I/O usage.

With the @DBNAME, @COUNT, and @ORDERBY parameters, you can quickly generate customized worst-performance reports. For example, the call

EXEC Examples.dbo.usp_Worst_TSQL
@DBNAME='AdventureWorks', @COUNT=6,
@ORDERBY='ACPU';

returns the top six T-SQL statements that have the highest average CPU usage in the AdventureWorks database. The call

EXEC Examples.dbo.usp_Worst_TSQL
@DBNAME='AdventureWorks', @COUNT=5;

returns the top five T-SQL statements that have the highest average I/O usage values in the Adventure- Works database. Figure 3 shows an excerpt of sample output from this query. (Only the first seven columns are displayed, and the last T-SQL statement is truncated.) As you can see, the T-SQL statement in the first row is by far the worst-performing in terms of average I/O.

In Figure 3, notice that some of the database names have an asterisk (*) after them. An asterisk indicates that the dbid column in the sys.db_exec_ plan_attributes DMV was used to identify the database name for that statement. When this occurs, the database name is the database context that was used when the statement was executed, so it might not reflect the actual database name if three-part naming conventions are used.

If you run usp_Worst_TSQL with no parameters, such as

EXEC Examples.dbo.usp_Worst_TSQL

the stored procedure returns all the T-SQL statements (sorted by average I/O usage) ran against all the databases on the server. These results can help identify the databases against which the most resource-intensive statements are being run.

I use usp_Worst_TSQL frequently and have encountered quirky results only one time. When I ran the stored procedure against a SQL Server 2005 instance running on my Windows XP laptop, it returned negative numbers for some of the columns. I believe this occurred because the sys.dm_exec_query_ stats DMV’s total_worker_time and total_elapsed_ time statistics contained negative numbers, which is related to SQL Server not being able to handle different CPU frequencies, as outlined in the Microsoft article “SQL Server timing values may be incorrect when you use utilities or technologies that change CPU frequencies” (support.microsoft.com/kb/931279). This problem didn’t occur when I ran usp_Worst_TSQL against a SQL Server 2008 instance on the same laptop or against any of my SQL Server 2005 instances running on Windows Server 2003 servers.

A Handy Report


The usp_Worst_TSQL stored procedure lets you quickly produce customized reports showing the poorest-performing T-SQL statements—all without having to remember or search through documentation on how to perform DMV, DMF, and JOIN operations. You can then share this information with the people who wrote the T-SQL statements (e.g., DBAs, programmers) so that they can fine-tune their T-SQL statements.

Discuss this Article 12

jaypat
on Nov 30, 2008
Nice script. Had some strange results (statement column was NULL) when I ran the code against a 3rd party DB. Seems these SPs were encypted.
cdeaton
on Nov 4, 2008
There appears to be an issue that I am looking into now. Msg 102, Level 15, State 1, Procedure usp_Worst_TSQL, Line 99 Incorrect syntax near '.'.
cdeaton
on Nov 4, 2008
This needs to be created in the the master database, or at least that works.
kraaitje
on Nov 11, 2008
Nice article. I tested it on our datamart and discoverd some nice facts.
knavish
on Feb 11, 2010
Very useful stored proc. Thanks.
orbhot
on Feb 6, 2009
I don't understand why you would divide by execution count. Shouldn't you multiply by exec count so that you get the most expensive queries that are run the highest number of times? Finding expensive queries that are only executed a few times is much less useful than finding even slightly expensive queries that run thousands of times per day.
greg.larsen@doh...
on Mar 17, 2009
The "Total" columns, like "total_logical_reads", or "total_logical_writes" are accumulated counts based on all executions. So in order to create the average counts per execution is why I divided by the execution_count. You do bring up a good point you want to not be concerned about commands that have only been executed a few times. You really want to focus in and tune those worst T-SQL commands that have executed 1000's of times, and tune those.
pjcwik
on Nov 11, 2008
What period of time is collected for the report?
lduvall
on Nov 4, 2008
I think your db has to be in 90 compatibility mode in order to do this. Can anybody confirm?
KBemowski
on Nov 11, 2008
I checked with Greg Larsen about the compatibility mode. He notes that this code works only on SQL Server 2005 databases in compatibility mode 90. In addition, I posted new code on Nov. 10 that takes care of the issue cdeaton found. Karen Bemowski, senior editor SQL Server Magazine, Windows IT Pro
kevindrys
on Nov 26, 2008
The StatisticsReturned.xls file does not appear to be included in 100201.zip.
Durendal (not verified)
on Dec 11, 2008
Hi Greg, Do you know why I get the error below when trying to compile the proc in SQL 2005? I beleive I have the code posted by Karen as I just pulled it today. Thanks. Msg 195, Level 15, State 10, Procedure usp_Worst_TSQL, Line 81 'OBJECT_SCHEMA_NAME' is not a recognized built-in function name.

Please or Register to post comments.

IT/Dev Connections

Las Vegas
September 30th - October 4th

Paul ThurottOur Experts will show you:
• Common SQL Server
Problems
• Best Practices for T-SQL
• SQL Server Integration
Services
• Database Development

Come See Michael Otey & Tim Ford in Person!

Early Registration Now Open

From the Blogs
May 21, 2013
blog

A Common Misconception about MAXDOP

Out of the box, SQL Server is (and has been) able to take advantage of multiple processors/cores without any effort on behalf of administrators....More
May 9, 2013
blog

My ISO 8601-Compliant Signature 2

My family recently just "officially" announced that we're in the process of adopting a child from South Africa. We're quite excited, of course, but there's a ton of paperwork to do—along with the need for gobs of signatures....More
May 8, 2013
blog

Use SSIS for ETL from Hadoop

In this blog post, Mark Kromer walks you through using SSIS as a way to use ETL techniques using Microsoft's Hadoop on Windows (HDInsight) as a source using Hive connectors...More
SQL Server Pro Forums

Get answers to questions, share tips, and engage with the SQL Server community in our Forums.