Wednesday, December 15, 2010

How to list current activity - Active SPID’s

What's going on with my server?

If you ever need to know what SPID’s are currently active _and_ are doing something that takes more than 1 second, then try this:

SELECT  r.cpu_time,

        r.logical_reads,

        r.session_id

INTO    #temp

FROM    sys.dm_exec_requests AS r

 

WAITFOR DELAY '00:00:01'

 

SELECT  SUBSTRING(h.text, ( r.statement_start_offset / 2 ) + 1,

                  ( ( CASE r.statement_end_offset

                        WHEN -1 THEN DATALENGTH(h.text)

                        ELSE r.statement_end_offset

                      END - r.statement_start_offset ) / 2 ) + 1) AS text,

        r.cpu_time - t.cpu_time AS CPUDiff,

        r.logical_reads - t.logical_reads AS ReadDiff,

        r.wait_type,

        r.wait_time,

        r.last_wait_type,

        r.wait_resource,

        r.command,

        r.database_id,

        r.blocking_session_id,

        r.granted_query_memory,

        r.session_id,

        r.reads,

        r.writes,

        r.row_count,

        s.[host_name],

        s.program_name,

        s.login_name

FROM    sys.dm_exec_sessions AS s

        INNER JOIN sys.dm_exec_requests AS r ON s.session_id = r.session_id

                                                AND s.last_request_start_time = r.start_time

        LEFT JOIN #temp AS t ON t.session_id = s.session_id

        CROSS APPLY sys.dm_exec_sql_text(r.sql_handle) h

 

WHERE is_user_process = 1

ORDER BY 3 DESC

 

 

DROP TABLE #temp

 

 

 

 

PerfMon for Dummies

Quest Software has released a nice overview of how to use PerfMon when analyzing SQL Server performance and health.

Tuesday, December 14, 2010

Top 100 most expensive queries–Profiler and Excel

Sometimes you need to analyze how the queries are behaving and get an understanding of what queries is taking most of the CPU time.  The key thought here is to slice the used CPU time per query with the current load. Note that this is not an exact science, but rather a qualified estimate of what is causing the current server load.

There are several ways of doing this, but I prefer to run a trace, parse the trace and import the result set into Excel for further analysis.  A complicating factor is whether your load consist of ad-hoc SQL or stored procedures. If your system consists of the latter, then the analysis job is straight forward. However, if your system has ad-hoc sql, then you need to parse and cleanup each sql statement. Itzik Ben-Gan has made a great CLR function for this, but I won’t cover this scenario for now.

Now, simply run a trace where you collect RPC:Completed and SP:Completed. Trace it to file and ensure you collect enough data. You should make a note of the current system load and consider whether it’s a representative load compared with the rest of the day or week. I usually sample for 10 minutes and end up with a file between 100 and 300 Gb.

Note that this may put some extra load on your server, but I have never been able to document a noticeable performance hit while sampling. This may, however, vary from system to system, load to load.

Make sure that you collect the following counters: EventClass, DBName, AppName, NTUserName, CPU, Reads, Writes, Duration, ObjectName, TextData, StartTime and EndTime.

An important question is whether you want to factor in a cost when the reported CPU cost is 0. In my experience this is the right thing to do because you get nothing for free. If you have 1000 queries per second, each with a CPU cost of 0, the sum cost is _not_  zero.

Simply run the query below and copy the result into Excel for further drill down. – VERY EASY-

Note that you need to have the trace files located on a SQL instance.

 

DECLARE @FileName VARCHAR(255)

SELECT  @Filename = 'C:\baseline traces\18082010_1427.trc'

SELECT  DATEDIFF([ss], MIN([starttime]), MAX(starttime)) AS [Seconds],

        COUNT(*) AS [Total],

        COUNT(*) / DATEDIFF([ss], MIN(starttime),

                            MAX(starttime)) AS s,

        MIN(starttime) AS [FROM],

        MAX(starttime) AS [TO]

FROM    ::

        FN_TRACE_GETTABLE(@Filename, DEFAULT) ;

 

WITH    a AS ( SELECT   CAST(COUNT(*) AS NUMERIC(38, 2))

                        / ( SELECT COUNT (*) FROM    :: FN_TRACE_GETTABLE (@Filename, DEFAULT) )

                        * 100 AS '%Calls',

                        COUNT(*) AS '#Calls',

                        AVG(duration) * COUNT(*) AS [Weighed AVG Duration],

                        CASE AVG(cpu)

                          WHEN 0 THEN 0.5 * COUNT(*)

                          ELSE AVG(cpu) * COUNT(*)

                        END AS [Weighed AVG CPU],

                        AVG(cpu) AS AvgCPU,

                        MIN(cpu) AS MinCPU,

                        MAX(cpu) AS MaxCPU,

                        ISNULL(AVG(duration) / 1000, 0) AS AvgDurationMS,

                        ISNULL(MIN(duration) / 1000, 0) AS MinDurationMS,

                        ISNULL(MAX(duration) / 1000, 0) AS MaxDurationMS,

                        AVG(READS) AS AvgReads,

                        MAX(READS) AS MaxReads,

                        AVG(writes) AS AvgWrites,

                        MAX(writes) AS MaxWrites,

                        ObjectName

               FROM     ::

                        FN_TRACE_GETTABLE(@Filename, DEFAULT)

               GROUP BY ObjectName)

    SELECT  CAST([%Calls] AS NUMERIC(38, 2)) AS '%Calls',

            [#Calls],

            [Weighed AVG Duration],

            [Weighed AVG CPU],

            CAST([Weighed AVG CPU]

            / ( SELECT SUM (a . [Weighed AVG CPU]) AS

                        [%Weighed AVG CPU] FROM a ) * 100 AS NUMERIC(38, 2)) AS [%Weighed AVG CPU],

            AvgCPU,

            MinCPU,

            MaxCPU,

            AvgDurationMS,

            MinDurationMS,

            MaxDurationMS,

            AvgReads,

            MaxReads,

            AvgWrites,

            MaxWrites,

            ObjectName

    FROM    a

    ORDER BY [%Weighed AVG CPU] DESC

Monday, December 13, 2010

Retrieving the execution plan by DMV

How can I retrieve the execution plan from a system without “EXECUTE” or “SELECT” rights on my database?

There are two ways of doing this. Either you can get the execution plan XML from SQL Profiler, or you can get it from the DMV dm_exec_query_plan.

If you want to use Profiler, you need the ALTE TRACE credential on the server. You simply set up a trace and use the ShowPlan XML event.

Another approach is to use the dm_exec_query_plan DMV:

SELECT  usecounts,

        cacheobjtype,

        objtype,

        text,

        OBJECT_NAME(st.objectid),

        qp.query_plan

FROM    sys.dm_exec_cached_plans cp

        CROSS APPLY sys.dm_exec_sql_text(plan_handle) st

        CROSS APPLY sys.dm_exec_query_plan(plan_handle) qp

WHERE   OBJECT_NAME(st.objectid) = 'my proc'

This approach requires that your login has the VIEW SERVER STATE credential.

When you execute it, the result set might look like this:

image

Then you simply need to click on the XML to study the execution plan

image