Finding Potential Bottlenecks with DMVs.

July 28, 2010

The following query is a great way to get a look into how your stored procedure driven application is performing. I wouldn’t recommend running this during your peak hours. What I have done is scheduled it to run in the off hours and store into a table in my dummy DB. I then query that table as it is less intensive then quering the DMVs. What this query shows me is area’s a I need to tune within my application. If a query is executed many times and has a high number of logical reads perhaps my index needs to be tuned. Same goes if I look into area’s where physical data processing is happening… If your data isn’t being found in the cache you may have a bottleneck or perhaps you are just pulling to much data. It’s also great to see which queries are executed most frequently as there is always room for improvement and it’s important to understand how your data is being accessed.

select
substring(text,patindex(‘%create %’,text),50),
 SUBSTRING(st.text, (qs.statement_start_offset/2) + 1,
    ((CASE statement_end_offset
        WHEN -1 THEN DATALENGTH(st.text)
        ELSE qs.statement_end_offset END
            – qs.statement_start_offset)/2) + 1) as statement_text,
db_name(dbid) DB,
creation_time,
last_execution_time,
execution_count,
(total_elapsed_time/execution_count)/1000000 as time
,total_physical_reads
,last_physical_reads
,min_physical_reads
,max_physical_reads
,total_logical_writes
,last_logical_writes
,min_logical_writes
,max_logical_writes
,total_logical_reads
,last_logical_reads
,min_logical_reads
,max_logical_reads
,getdate()
FROM sys.dm_exec_query_stats as qs
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) as st
where db_name(dbid) =’YourDB’


Finding Procedures with largest Compile times

June 7, 2010

First you need to store the sql server plan cache into a table..

You can create a view then store the contents of that view into a table or query your view directly.
Create this in the master database

CREATE VIEW [dbo].[MYCache]
as
SELECT sp.*
FROM sys.dm_exec_cached_plans as cp
CROSS APPLY SqlAndPlan(cp.plan_handle) as sp

You can select the above data into a table for querying.. The reason I suggest ths is the cache querying can be intensive depending on the number of objects in your cache.

The below query gives you Compile Time, Estimated Rows, and Compile Memory..
You can use this information to determine your worst performing stored procedures.

SELECT SUBSTRING(TEXT, CHARINDEX(‘CREATE PROCEDURE’, text)+16,50) as ProcName,
text,
query_plan.value(‘
     declare namespace AWMI=”http://schemas.microsoft.com/sqlserver/2004/07/showplan”;
     sum(//AWMI:RelOp/@EstimateRows)’, ‘float’) as EstRows,
query_plan.value(‘
     declare namespace AWMI=”http://schemas.microsoft.com/sqlserver/2004/07/showplan”;
     sum(//AWMI:QueryPlan/@CompileMemory)’, ‘float’) as EstMemory,
query_plan.value(‘
     declare namespace AWMI=”http://schemas.microsoft.com/sqlserver/2004/07/showplan”;
     sum(//AWMI:QueryPlan/@CompileTime)’, ‘float’) as CompileTime
FROM PlayDB..Mycache


Blocking Monitor

October 2, 2009

I wanted to share a little something we put together to monitor blocking on our SQL 2005 servers. Every once in awhile the blocking gets out of control and when it does we get these emails so we can quickly jump in and troubleshoot before the Help desk tickets start rolling in.  Create this in your master database be sure to change the database name where it says YOURDB. Create a SQL Server job that runs constantly. In the Job SQL put the following infinite loop to call the proc below:

declare @count int
set @count = 5000000
WHIle @count > 0
BEGIN
waitfor delay ’00:00:15′
exec [Proc_LeadBlocker] 0, ‘YOUR MAIL PROFILE’, ‘Youremail@email.com’
end

 

CREATE  PROCEDURE [dbo].[Proc_LeadBlocker]
(@maxtime int = 0,@MailProfile varchar(100),@recipients varchar(255) )   
as   
--=======================================================================   
-- Proc Name : sp__leadblocker   
-- Description : This procedure will report processes that are blocking   
--    other processes and processes that are being blocked   
--    
-- Author : Motherofallgeeks.com
--=======================================================================   
 
--DECLARE VARIABLES   
DECLARE @BLKemailmsg varchar(1000)   
DECLARE @WAITemailmsg varchar(1000)   
DECLARE @message varchar(max)
   
--CHECK FOR BLOCKING   
IF EXISTS (select 1 FROM sys.dm_exec_requests  
     WHERE Session_ID in
      (SELECT blocking_session_id 
      FROM sys.dm_exec_requests 
      WHERE (wait_time/15000) > @maxtime))    
BEGIN  
 --BUILD BLOCKING PROCESSES EMAIL MSG   
 select @BLKemailmsg = 'The Following Processes are Blocking other Processes:(BLOCKER)  <br>' 
 select @BLKemailmsg = @BLKemailmsg+    
   '<b> SPID: </b>'+ convert(varchar(5),DR.Session_ID) +  '<br>' +
   '<b> STATUS: </b>' + DS.status +    '<br>' +
   ' <b>CMD: </b>' +DR.command+    '<br>' +
   '<b> DB:</b> '+ db_name(DR.database_id) +    '<br>' +
   '<b> LOGIN:</b> '+ DS.login_name +    '<br>' +
   '<b> HOSTNAME:</b> '+ DS.host_name +    '<br>' +
   '<b> LAST_BATCH_TIME: </b>'+ convert(varchar(20),Ds.last_request_Start_time,113)+   '<br>' +
 '<b> wAIT rESOURCE: </b>'+wait_resource + '<br>' +
 '<b> last_wait_type: </b>'+last_wait_type + '<br>' +
   ' <b> SQL Statement: </b>' +  (select name from [YOURDB].sys.objects where object_id=s2.objectid)+ ' '+ SUBSTRING(s2.text,  statement_start_offset / 2, ( (CASE WHEN statement_end_offset = -1 THEN (LEN(CONVERT(nvarchar(max),s2.text)) * 2) ELSE statement_end_offset END)  - statement_start_offset) / 2)    +  --convert(varchar(8000),s2.text) +   '<br>'
   '<HR>'
FROM sys.dm_exec_requests DR  INNER JOIN sys.dm_exec_sessions DS  ON DR.Session_id = DS.Session_id
CROSS APPLY sys.dm_exec_sql_text(dr.sql_handle) AS s2 
WHERE DR.Session_ID in
 (SELECT blocking_session_id
   FROM sys.dm_exec_requests 
   WHERE (wait_time/15000) > @maxtime)   
         
   
 --BUILD WAITING PROCESSES EMAIL MSG   
 select @WAITemailmsg = ' The Following Processes are Waiting for Resources:(BEING BLOCKED) <br> '
 select @WAITemailmsg = @WAITemailmsg +
   '<b> SPID: </b>'+ convert(varchar(5),DR.Session_ID) +    '<br>' +
   '<b>  CMD: </b>' +DR.command+    '<br>'+
   '<b>  DB:</b> '+ db_name(DR.database_id) +   '<br>' + 
   '<b>  LOGIN:</b> '+ DS.login_name +   '<br>' + 
   ' <b> WAITTIME:</b> '+ convert(varchar(4),DR.wait_time/15000)+   '<br>' +
   ' <b> BLOCKED BY:</b> '+ convert(varchar(5),DR.blocking_session_id) +   '<br>'   + 
 '<b> wAIT rESOURCE: </b>'+wait_resource + '<br>' +
 '<b> last_wait_type: </b>'+last_wait_type + '<br>' +
 ' <b> SQL Statement: </b>' +  (select name from [YOURDB].sys.objects where object_id=s2.objectid)+' '+  SUBSTRING(s2.text,  statement_start_offset / 2, ( (CASE WHEN statement_end_offset = -1 THEN (LEN(CONVERT(nvarchar(max),s2.text)) * 2) ELSE statement_end_offset END)  - statement_start_offset) / 2)    + '<br>' --convert(varchar(8000),s2.text) +   '<br>'
FROM sys.dm_exec_requests DR 
INNER JOIN sys.dm_exec_sessions DS  ON DR.Session_id = DS.Session_id
CROSS APPLY sys.dm_exec_sql_text(dr.sql_handle) AS s2 
WHERE   (DR.wait_time/15000) > @maxtime
 and DR.blocking_session_id <> 0
SELECT @message =  @BLKemailmsg + ' ' + @WAITemailmsg
      exec msdb..sp_send_dbmail  @profile_name =  @MailProfile
     ,  @recipients =  @recipients
     ,  @subject =  'Blocking Processes'
     ,  @body_format =  'HTML'
     ,  @body = @message
  ,@query_result_header = 0
 END
--

Simple Space Checker

March 7, 2009

I recently had someone ask me how to I see my actual usage of data and index files without using the GUI.  Well I am going to tell you that and I am also going to tell you how to set up a monitor job to alert  you when your file is approaching it’s capacity.  Why would you want to do that when you have AutoGrow? The first reason is that Auto grow will trigger an ALTER Database statement. You have no control over the time of day that this alter will fire.  Alter will Lock your system up until it has completed. This type of maintenance should be monitored and performed at a time when system impact will be less.  If auto grow is enabled and you are not monitoring your database space you could eat up all of the drive space and crash the server. DBA’s should be aware of how fast your systems are growing and proactively add the space as needed.

That being said. This script was developed for SQL Server 2005. It uses undocumented processes which are not recommended for use by microsoft because they may be removed at anytime.

There is an undocumented DBCC command which has been around for quite some time. We will use this command dbcc showfilestats as the basis of our script.

We are going to create a system stored procedure. That way you can run this proc from any database without having to create it in all databases. It makes maintenance much easier. You can schedule it to run from SQL Agent every 30 minutes and it will send you a mail based on your file reaching 90%.

Enjoy!

set ANSI_NULLS ON
set QUOTED_IDENTIFIER ON
go

/*******************************************************************************************
* proc_checkspace
* Created By: MotherofallGeeks
* Created Date: March 2008
* Purpose check available Free space in database and send alert
* exec proc_CheckSpace ‘MyMailProfile’ , ‘Mother@motherofallgeeks.com’
*/

CREATE PROC [dbo].[sp_CheckSpace]

@MailProfile varchar(max),
@recipients varchar(max)
AS
BEGIN
SET NOCOUNT ON

DECLARE @DataUsedPercent float
DECLARE @IndexUsedPercent float
DECLARE @FileName varchar(max)
DECLARE @Size numeric
DECLARE @IndexSize float
DECLARE @UsedSpace float

DECLARE @tmpspc table
(Fileid int, FileGroup int,
TotalExtents int,
UsedExtents int,
Name sysname,
FileName nchar(520))

INSERT @tmpspc EXEC (‘dbcc showfilestats’)

SELECT
@FileName = s.physical_name ,
@Size = convert (dec (15,2),s.size) * 8192 / 1048576,
@UsedSpace =CAST(tspc.UsedExtents*convert(float,64) /1024 AS float) ,
@DataUsedPercent =(CAST(tspc.UsedExtents*convert(float,64) /1024 AS float) / (convert (dec (15,2),s.size) * 8192 / 1048576) ) * 100
FROM
sys.filegroups AS g
INNER JOIN sys.master_files AS s ON (s.type = 0 and s.database_id = db_id() and (s.drop_lsn IS NULL)) AND (s.data_space_id=g.data_space_id)
INNER JOIN @tmpspc tspc ON tspc.Fileid = s.file_id
WHERE
(CAST(cast(g.name as varbinary(256)) AS sysname)=N’PRIMARY’)

IF (@DataUsedPercent > 90)
BEGIN
DECLARE @Body varchar(max)
SET @Body = db_name()+’ Free Space is < 10% in the following File: ‘ + char(13) + @FileName +char(13)+
+ ‘Size MB =’+convert(varchar(10),@Size) + ‘ Used Space MB = ‘+convert(varchar(10),@UsedSpace)
+ ‘ %Used = ‘+ convert(varchar(10),@DataUsedPercent)

exec msdb..sp_send_dbmail @profile_name = @MailProfile
, @recipients = @recipients
, @subject = ‘Free Space Alert’
, @body_format = ‘TEXT’
, @body = @Body
,@query_result_header = 0
END

SET @FileName = ”
SET @Size = 0
SET @UsedSpace =0

SELECT
@FileName = s.physical_name ,
@Size = convert (dec (15,2),s.size) * 8192 / 1048576,
@UsedSpace =CAST(tspc.UsedExtents*convert(float,64) /1024 AS float) ,
@IndexUsedPercent =(CAST(tspc.UsedExtents*convert(float,64) /1024 AS float) / (convert (dec (15,2),s.size) * 8192 / 1048576) ) * 100
FROM
sys.filegroups AS g
INNER JOIN sys.master_files AS s ON (s.type = 0 and s.database_id = db_id() and (s.drop_lsn IS NULL
)) AND (s.data_space_id=g.data_space_id)
INNER JOIN @tmpspc tspc ON tspc.Fileid = s.file_id
WHERE
(CAST(cast(g.name as varbinary(256)) AS sysname)=N’INDEX’)
IF (@IndexUsedPercent > 90)
BEGIN
SET @Body = db_name()+’ Free Space is < 10% in the following File: ‘ + char(13) + @FileName +char(13)+
+ ‘Size MB =’+convert(varchar(10),@Size) + ‘ Used Space MB = ‘+convert(varchar(10),@UsedSpace)
+ ‘ %Used = ‘+ convert(varchar(10),@indexUsedPercent)

exec msdb..sp_send_dbmail @profile_name = @MailProfile
, @recipients = @recipients
, @subject = ‘Free Space Alert’
, @body_format = ‘TEXT’
, @body = @Body
,@query_result_header = 0
END

END

 

GO

EXECUTE sp_ms_marksystemobject '[sp_CheckSpace]'