Wednesday, 26 September 2012

SQL Server: Part 4 : Approaching Database Server Performance Issue

In the last three parts, we have discussed about different queries that can be used to list the current state of the database server. In this post let us discuss about listing execution stats from the plan cache.

The below query will help us to list the CPU intensive queries from your  plan cache.

List heavy query based on CPU/IO. Change the order by clause appropriately

DB_NAME(qt.dbid) AS DatabaseName
,DATEDIFF(MI,creation_time,GETDATE()) AS [Age of the Plan(Minutes)]
,last_execution_time AS [Last Execution Time]
,qs.execution_count AS [Total Execution Count]
,CAST((qs.total_elapsed_time) / 1000000.0 AS DECIMAL(28,2)) [Total Elapsed Time(s)]
,CAST((qs.total_elapsed_time ) / 1000000.0/ qs.execution_count AS DECIMAL(28, 2)) AS [Average Execution time(s)]
,CAST((qs.total_worker_time) / 1000000.0 AS DECIMAL(28,2)) AS [Total CPU time (s)]
,CAST(qs.total_worker_time * 100.0 / qs.total_elapsed_time AS DECIMAL(28,2)) AS [% CPU]
,CAST((qs.total_elapsed_time - qs.total_worker_time)* 100.0 /qs.total_elapsed_time AS DECIMAL(28, 2)) AS [% Waiting]
,CAST((qs.total_worker_time) / 1000000.0/ qs.execution_count AS DECIMAL(28, 2)) AS [CPU time average (s)]
,CAST((qs.total_physical_reads) / qs.execution_count AS DECIMAL(28, 2)) AS [Avg Physical Read]
,CAST((qs.total_logical_reads) / qs.execution_count AS DECIMAL(28, 2))  AS [Avg Logical Reads]
,CAST((qs.total_logical_writes) / qs.execution_count AS DECIMAL(28, 2)) AS [Avg Logical Writes]
, SUBSTRING (qt.TEXT,(qs.statement_start_offset/2) + 1,((CASE WHEN qs.statement_end_offset -1
ELSE qs.statement_end_offset
END - qs.statement_start_offset)/2) + 1) AS [Individual Query]

, qt.TEXT AS [Batch Statement]
, qp.query_plan
WHERE qs.total_elapsed_time > 0
[Total CPU time (s)] 
--[Avg Physical Read]
--[Avg Logical Reads]
--[Avg Logical Writes]
--[Total Elapsed Time(s)]
--[Total Execution Count]

Let us discuss the output columns.
Column Name Description
DatabaseNameDatabase Context of the execution plan.
Age of the Plan(Minutes) Age of the plan in the plan cache in minutes.
Last Execution Time Date and Time of the last execution of this plan.
Total Execution CountTotal number of execution after the last compilation
Or Total number of execution in the last [Age of the Plan(Minutes)]
(since it was last compiled)

Total Elapsed Time(s)
Total time (second) took to execute this plan [Total Execution Count] times
Execution time(s)
Average Time(seconds) took for single execution of this plan
Total CPU time (s) Total CPU time(seconds) took to  execute this plan [Total Execution Count] times
% CPU Percentage of CPU time compared to  [Total Elapsed Time(s)]

% Waiting 
Percentage of waiting time(wait for resource)  compared to  [Total Elapsed Time(s)]

CPU time 
average (s)
Average CPU time (Seconds) used for single exection

Avg Physical Read
Average number of Physical read for single execution

Avg Logical Reads
Average number of Logical read for single execution

Avg Logical Writes
Average number of Logical writes for single execution

Maximum number of physical reads that this plan has ever performed during a single execution.

Maximum number of logical reads that this plan has ever performed during a single execution.

Maximum number of logical writes that this plan has ever performed during a single execution.

Individual Query
Part of Batch Statement 

Batch Statement
Batch Query

XML execution . On clicking this we can see the graphical execution plan

I used to  analyse  the first five to ten records ( in each category by changing the order by clause) to see  procedures implementation. Most of the time I used to find some thing wrong with the procedure  like unnecessary temp table usage, distinct clause , cursors, table joining with out proper joining condition,no proper indexing etc. The other issue usually happen is, enormous calls to database for single procedure (CPU cost and execution time might less). This might be a wrong implementation, which should be fixed by discussing with development team. Usually this can be fixed by adding some types of caching  in application.Some time calls to the database is only to check if there is any change in the result data. Some thing like if there is new records in a table, it should be processed immediately. To achieve this, application might be querying the table to find the unprocessed record multiple time in a second, This can be fixed by implementing some kind of asynchronous call to the application by the application which inserts the data into this table or by implementing the notification event using SqlDependency available in the .Net frame work.

If you liked this post, do like my page on FaceBook


  1. Hello Nelson,
    I've been using the above query in sql server 2008 for couple of years without any issue. We recently upgraded to SQL Server 2014 standard edition and I migrated this query to 2014. Now this query takes really long time. What could be the reason?



  2. I loved the way you discuss the topic great work thanks for the share, Let me share this, Hadoop training in pune

  3. Thank you for this valuable information. The information you shared is very interesting. Get your business to the next level in simple steps. We provides lowest price of erp software Software for our clients.
    erp software in chennai | erp providers in chennai | online events registration




  7. Interesting post! This is really helpful for me. I like it! Thanks for sharing!

    Webseiten Gestaltung Lüdenscheid

  8. Your website content nice nice and interesting to observe.
    Internet Marketing Dienstleistungen

  9. شحن عفش من المدينة لمصر
    ارخص نقل عفش بمكة ارخص نقل عفش بمكة
    نقل عفش من جدة الى الدمام نقل عفش من جدة الى الدمام
    نقل عفش من الرياض الى المدينة المنورة نقل عفش من الرياض الى المدينة المنورة
    نقل عفش من الدمام الى مكة نقل عفش من الدمام الى مكة
    نقل عفش من الرياض الى الدمام نقل عفش من الرياض الى الدمام

  10. This blog is the general information for the feature. You got a good work for these blog.We have a developing our creative content of this mind.Thank you for this blog. This for very interesting and useful.
    Blockchain online training

  11. I just loved your article on the beginners guide to starting a blog.If somebody take this blog article seriously in their life, he/she can earn his living by doing blogging.thank you for thizs article. blockchain online training

  12. Thanks for Sharing This Article.It is very so much valuable content. I hope these Commenting lists will help to my website
    blockchain online training
    best blockchain online training
    top blockchain online training

  13. As in the case of a limited liability company, the owners of the company's shares can be both legal entities and individuals. But, unlike a limited liability company, shares of a JSC can be bought and sold publicly. The maximum number of shares is not limited and more shares may be issued during the life of the company. There are several types of shares, and usually the rights of shareholders to vote and receive dividends depend on the category of shares. Generally, shareholders have the right to express their opinions on the direction of the business and other matters such as distribution of profits and appointment of the council. All decisions of shareholders are made at the meeting of shareholders.