Analyzing Slow Stored Procedures or Queries
After you identify that a
particular stored procedure is running slowly, what should you do? You
might want to look at the estimated execution plan for the stored
procedure, looking for table scans and sections of the plan that have a
high cost percentage. But what if the execution plan has no obvious
problems? This is the time you should consider using the SQL Profiler.
You can set up a trace on the
stored procedure that captures the execution of each statement within
it, along with its duration, in milliseconds. Here’s how:
Create a new trace, using the TSQL_Duration template.
Add the SP:StmtCompleted event from the stored procedure event class to the trace.
Add a filter on the Duration column with the duration not equal to 0. You can also set the filter to a larger number to exclude more of the short-running statements.
If you plan to run the procedure from SSMS, you might want to add a filter on the SPID
column as well. Set it equal to the process ID for your session; the
SPID is displayed at the bottom of the SSMS window next to your
username, in parentheses. This traces only those commands that are
executed from your SSMS query editor window.
When you run the trace
and execute the stored procedure, you see only those statements in the
procedure that have nonzero duration. The statements are listed in
ascending duration order. You need to look to the bottom of the Profiler
output window to find your longer-running statements. You can isolate
these statements, copy them to SSMS, and perform a separate analysis on
them to determine your problem.
You can also add showplan
events to your Profiler trace to capture the execution plan as the trace
is running. SQL Server now has showplan events that capture the
showplan results in XML format. Traces with this type of XML output can
have a significant impact on server performance while they are running
but make the identification of poorly performing statements much easier.
When you are tracing stored procedure executions, it is a good idea to
add a filter on the specific stored procedure you are targeting to help
minimize the impact on performance.
After you run a trace with an
XML showplan event, you can choose to extract the showplan events to a
separate file. To do so, in the SQL Server Profiler you select File,
SQL Server Events, Extract Showplan Events. At this point, you can save
the showplan events in a single file or to a separate file for each
event. The file(s) is saved with a SQLPlan file extension. This file can then be opened in SSMS, and the graphical query execution plan is displayed.
Deadlocks are a common
occurrence in database management systems (DMBSs). In simple terms,
deadlocks occur when a process (for example, SPID 10) has a lock on a
resource that another process (for example, SPID 20) wants. In addition,
the second process (SPID 20) wants the resource that the first process
has locked. This cyclic dependency causes the DBMS to kill one of the
processes to resolve the deadlock situation.
Resolving deadlocks and
identifying the deadlock participants can be difficult. In SQL Server
2008 and past versions, trace flag 1204 can be set to capture the
processes involved in the deadlock. The output is text based but
provides valuable information about the types of locks and the
statements that were executing at the time of the deadlock. In addition
to this approach, SQL Server 2008 offers the capability to capture
detailed deadlock information via the SQL Server Profiler. This type of
tracing can be accomplished as follows:
Create a new trace, using a Blank template; this leaves the selection of all the events, data columns, and filters to you.
Add the Locks:Deadlock graph event to the trace from the Locks category. An additional tab named Event Extraction Settings appears on the Trace Properties window.
the Save Deadlock XML Events Separately check box. This causes the
deadlock information to be written to a separate file. You could also
export the results after the trace has been run by using the File,
When you run this trace, it
captures any deadlock event that occurs and writes it to the XML file
specified. To test this, you can open two query editor windows and
execute the following statements, in the order listed, and in the query
-- In Query Window # 1
UPDATE HumanResources.Employee SET ModifiedDate = GETDATE()
-- In Query Window # 2
UPDATE HumanResources.Department SET ModifiedDate = GETDATE()
SELECT * FROM HumanResources.Employee
-- In Query Window # 1
SELECT * FROM HumanResources.Department
When the deadlock occurs, the results pane for one of the query windows contains a message similar to the following:
Msg 1205, Level 13, State 51, Line 3
Transaction (Process ID 55) was deadlocked on lock resources with another
process and has been chosen as the deadlock victim. Rerun the transaction.
When the row with the Deadlock graph event is selected in the Profiler output grid, a graph like the one shown in Figure 1 is displayed.
Figure 1. Output from the Deadlock graph event.
The Deadlock graph
event contains a wealth of information about the deadlock occurrence.
The oval nodes represent the processes involved in the deadlock. The
oval with an X mark across it is the deadlock victim that had its
process killed. The other oval represents the process that was allowed
to complete when the deadlock was resolved. The boxes in the middle of
the graph display lock information about the specific objects involved
in the deadlock.
The graph is
interactive and displays relevant information about the processes that
were running when the deadlock occurred. For example, when you mouse
over the oval nodes, pop-up text appears, displaying the SQL statement
that was executing at the time of the deadlock. This is the same type of
information that is displayed when the aforementioned trace flag is
used, but the graph tends to be easier to decipher.