11
votes

We have a Windows 2008 R2 Server with a SQL Server 2008 in it. That server has multiple .net sites that have SQL server databases on it.

We are currently experiencing an average CPU usage of 95%, and SQL Server is responsible for most of that usage.

I would like to identify which site is responsible for this so we can either optmize it or move it to another server. But I didnt find any direct way of looking this.

I've been looking if I could find:

  • The database that is getting the most CPU intensive queries
  • The process that is responsible for CPU intensive queries

One thing that also complicates the things is that we have multiple sites and "crons" using the same database. So once I identify the database I would also need to get some hints of which site/cron is responsible for it.

I would really appreciate any help on this as this issue is making our sites really slow...

Thanks

2

2 Answers

28
votes

You can identify costly queries (and the databases they are associated with) using the DMVs, e.g. from this TechNet article:

SELECT TOP 50
 [Average CPU used] = total_worker_time / qs.execution_count,
 [Total CPU used] = total_worker_time,
 [Execution count] = qs.execution_count,
 [Individual Query] = SUBSTRING (qt.text,qs.statement_start_offset/2, 
         (CASE WHEN qs.statement_end_offset = -1 
            THEN LEN(CONVERT(NVARCHAR(MAX), qt.text)) * 2 
          ELSE qs.statement_end_offset END - 
qs.statement_start_offset)/2)
,[Parent Query] = qt.text
,DatabaseName = DB_NAME(qt.dbid)
FROM sys.dm_exec_query_stats qs
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) as qt
ORDER BY [Average CPU used] DESC;

These will tell you about heavy hitter queries, but unfortunately it won't pinpoint a database that might have very high volume of small queries that are using small bits of CPU individually but large bits in aggregate. You can do that with this query from Glenn Allan Berry's DMV queries:

WITH DB_CPU_Stats
AS
(SELECT DatabaseID, DB_Name(DatabaseID) AS [DatabaseName], 
  SUM(total_worker_time) AS [CPU_Time_Ms]
 FROM sys.dm_exec_query_stats AS qs
 CROSS APPLY (SELECT CONVERT(int, value) AS [DatabaseID] 
              FROM sys.dm_exec_plan_attributes(qs.plan_handle)
              WHERE attribute = N'dbid') AS F_DB
 GROUP BY DatabaseID)
SELECT ROW_NUMBER() OVER(ORDER BY [CPU_Time_Ms] DESC) AS [row_num],
       DatabaseName, [CPU_Time_Ms], 
       CAST([CPU_Time_Ms] * 1.0 / SUM([CPU_Time_Ms]) 
       OVER() * 100.0 AS DECIMAL(5, 2)) AS [CPUPercent]
FROM DB_CPU_Stats
WHERE DatabaseID > 4 -- system databases
AND DatabaseID <> 32767 -- ResourceDB
ORDER BY row_num OPTION (RECOMPILE);

Neither of these queries identifies the application that ran them, and the DMVs used don't store that information (you would have to catch the queries in the act and note the application name in sys.dm_exec_sessions, or review a trace).

Of course you can automate this work with a variety of 3rd party performance tools on the market (disclaimer: I work for one of them, SQL Sentry, who produces Performance Advisor, which does all of the above, including keeping track of high-cost queries and maintaining the information about which database they ran in and what application called them).

1
votes

Alternatively you can use the Activity monitor to view the health status of your servers. From there you will be able to single out long running queries, any locks such as row lock, table lock etc etc

http://www.mssqltips.com/sqlservertip/1917/performance-analysis-using-sql-server-2008-activity-monitor-tool/