Parsing the Blocked Process report

October 20, 2011

As you know the new blocked process report in SQL Server 2005 and beyond is awesome. Now if you have lots of blocked processes being reported it can be a bit overwheleming. How can you quickly tell if it’s the same senario over and over again or if your hitting multiple scenarios. I don’t know about you but I’m cheap and I don’t want to buy a tool so I’ll tell you how to do this yourself.

1) Run a profiler trace for blocked process event on the SQL Instance in question.
2) Save the profile to a table.
3) You need to save the data again from the table in step 2 as xml just use the textdata column but it needs to be an XML Data Type.

Here is a sample.

select DATEDIFF(ss,Starttime,EndTime)DurationInSec,
StartTime,
CONVERT(xml,textdata) As BlockedRPT, Servername
INTO ALLBLOCKS
from dbo.myProfileTable
where EventClass = 137

4) Run the following SQL to get the distinct Blocking and being Blocked statements

SELECT
distinct
X.x.value(‘data(.)’,'varchar(5000)’) AS BlockedSQLcmd,
Y.x.value(‘data(.)’,'varchar(5000)’) AS BlockingSQLcmd
FROM ALLBLOCKS a
CROSS APPLY
blockedRpt.nodes(‘/blocked-process-report/blocked-process/process’) AS X(x)
CROSS APPLY
blockedRpt.nodes(‘/blocked-process-report/blocking-process/process’) AS Y(x)

4) Run the following SQL to get all the details you need about each blocked process report.

SELECT
convert(date,starttime),
X.x.value(‘@currentdb’, ‘nvarchar(45)’) Blockeddb,
X.x.value(‘@waitresource’, ‘nvarchar(45)’) BlockedObject ,
X.x.value(‘@lockMode’, ‘nvarchar(45)’) BlockedBlockLockMode,
X.x.value(‘@hostname’,'nvarchar(45)’) BlockedFromHOst,
X.x.value(‘@loginname’,'nvarchar(45)’) BlockedFromLogin,
X.x.value(‘@isolationlevel’,'nvarchar(45)’) BlockedFromIso,
X.x.value(‘data(.)’,'varchar(5000)’) AS BlockedSQLcmd,

Y.x.value(‘@waitresource’, ‘nvarchar(45)’) BlockingObject ,
Y.x.value(‘@hostname’,'nvarchar(45)’) BlockingFromHOst,
Y.x.value(‘@loginname’,'nvarchar(45)’) BlockingFromLogin,
Y.x.value(‘@isolationlevel’,'nvarchar(45)’) BlockingFromIso,
Y.x.value(‘data(.)’,'varchar(5000)’) AS BlockingSQLcmd
FROM ALLBLOCKS a
CROSS APPLY
blockedRpt.nodes(‘/blocked-process-report/blocked-process/process’) AS X(x)
CROSS APPLY
blockedRpt.nodes(‘/blocked-process-report/blocking-process/process’) AS Y(x)


Checking Index Fragmentation

October 18, 2011

If your not monitoring your indexes on a regular basis shame on you, you should be. Depending on how many databases you are supporting this could end up being extremely tiedious. So here is what I do and you can tailor the process to your env.

1) Each production server I support has a DBA database on it.

2) Create the table IndexStats in each of the DBA databases (scripts below)

3) Create a job with the script below to capture the index statisics . (I do it once a week)

4) Now here it’s up to you on how you want to do this. I have a huge number of servers that I support so I transfer the statistics from each individual server to a central repository. I use an SSIS package which connects to the table in each database and dumps it into a table of the same format on my repository. The SSIS package uses Simple Data flows to do this and is pretty straight forward. I’m not going to go into the package in this post. If you need assistance on creating data flows in SSIS there are plenty of resources out there.

5) Create the report stored procedure to email you indexes which need to be rebuilt and schedule it based on your needs. I run it once a week then rebuild the indexes that weekend on the server in questions.

Script 1 Create Table to hold your statistics in your DBA database.

CREATE TABLE [dbo].[IndexStats](
[SQLInstance] [varchar](160) NULL,
[DatabaseName] [varchar](160) NULL,
[TableName] [varchar](160) NULL,
[IndexName] [varchar](160) NULL,
[IndexType] [varchar](160) NULL,
[Databaseid] [smallint] NULL,
[object_id] [int] NULL,
[index_id] [int] NULL,
[user_seeks] [bigint] NULL,
[user_scans] [bigint] NULL,
[user_lookups] [bigint] NULL,
[user_updates] [bigint] NULL,
[last_user_seek] [datetime] NULL,
[last_user_scan] [datetime] NULL,
[last_user_lookup] [datetime] NULL,
[last_user_update] [datetime] NULL,
[system_seeks] [bigint] NULL,
[system_scans] [bigint] NULL,
[system_lookups] [bigint] NULL,
[system_updates] [bigint] NULL,
[last_system_seek] [datetime] NULL,
[last_system_scan] [datetime] NULL,
[last_system_lookup] [datetime] NULL,
[last_system_update] [datetime] NULL,
[rows] [int] NULL,
[StatisticsCaptured] [date] NULL,
[avg_fragmentation_in_percent] [float] NULL,
[page_count] [int] NULL,
[Index_Depth] [int] NULL,
[Index_level] [int] NULL,
[Avg_record_Size_in_bytes] [int] NULL
) ON [PRIMARY]GO

SET ANSI_PADDING OFF
GO

ALTER TABLE [dbo].[IndexStats] ADD DEFAULT (getdate()) FOR [StatisticsCaptured]
GO

Script 2 Schedule this script from SQL Agent to populate your IndexStats Table. I delete data from this table since my data is moved into a central repository but if you are not doing that then you can remove the delete part of the script

insert into MyDBADB..IndexStats
exec
sp_msforeachdb
‘use ?
DECLARE @dbid int
select @dbid = db_id(”?”)
select
DISTINCT
@@SERVERNAME as SQLInstance,
”?” as DB,
OBJECT_NAME(a.object_id) as [TableName],
B.name as [Index],
B.type_desc as [IndexType],
A.*,
p.rows,
getdate(),
OS.avg_fragmentation_in_percent,
OS.page_count,
OS.Index_Depth,
OS.Index_level,
OS.Avg_record_Size_in_bytes
FROM ?.sys.dm_db_index_usage_stats a
INNER JOIN ?.sys.indexes B on a.object_id = B.object_id and a.index_id = B.index_id
inner join ?.sys.partitions p on B.object_id =p.object_id and B.index_id =p.index_id
INNER JOIN ?.sys.dm_db_index_physical_stats(@dbid,NULL,NULL,NULL,”SAMPLED”) OS on
A.object_id = OS.Object_id and A.index_id =OS.Index_id
WHERE
OBJECT_NAME(a.object_id) not like ”sys%” and OBJECT_NAME(a.object_id) not like ”spt%”
and OBJECT_NAME(a.object_id) not like ”queue%”
and a.database_id = DB_ID(”?”)
order by B.namedelete from MyDBADB..IndexStats
where StatisticsCaptured > GETDATE() -14

Script 3 Create the following stored procedure on your repository and schedule it to run as you see fit. This will alert you on the indexes with Fragmentation percent greater then 50.

/******************************************************************************************************
* Created By: MotherofAllGeeks.Com
* Created on: 3/2011
* Purpose gather space information for trending or possibly alerting
* Create it in master and it will gather stats for all databases
* Sample Call proc_getdatabasespace_r
* Prereq is that you must have a DBADB and you must have created FileStats table in MyDBADb.
* exec [proc_GetFragmentationReport_r] 7,’Mom@motherofallGeeks.com’, ‘MyMailProfile’
******************************************************************************************************/
CREATE PROCEDURE [dbo].[proc_GetFragmentationReport_r]
@days int ,
@recipients varchar(255),
@profile varchar(255)

AS

BEGIN
SET NOCOUNT ON

BEGIN TRY

BEGIN
DECLARE @tableHTML NVARCHAR(MAX), @currentDate date, @usagepercentage int

SET @tableHTML =
N’

‘+ N’

‘+N’Database’+N’CountofFragmenedIndexes’+N’

‘ +CAST ((SELECTtd = convert(varchar(30),sqlinstance) ,” ,td = convert(varchar(60),databasename),” ,td = convert(varchar(24),counttables) ,”FROM (select sqlinstance,databasename,count(tablename) counttablesfrom indexstatswhere avg_fragmentation_in_percent > 50and StatisticsCaptured > GETDATE() – @daysgroup by sqlinstance, databasename) Aorder by counttables descFOR XML PATH(‘tr’), TYPE) as NVARCHAR(max) ) + N’

SQLInstance

IF (@tableHTML is not null)
BEGIN

declare @subject varchar(55)
SELECT @subject = ‘Fragmented Indexes ‘
exec msdb.dbo.sp_send_dbmail
@profile_name = @profile,
@recipients = @recipients,
@subject = @subject,
@body = @tableHTML,
@body_format = ‘HTML’
END
END

END TRY

BEGIN CATCH

DECLARE @ErrorMessage varchar(max)

SELECT @ErrorMessage =
‘ErrorNumber:’ + convert(varchar(7),ERROR_NUMBER()) + ‘
‘ +
‘ErrorSeverity:’ + convert(varchar(7),ERROR_SEVERITY()) +’
‘+
‘ErrorState:’ + convert(varchar(7),ERROR_STATE()) +’
‘+
‘Calling Procedure:’ + CONVERT(VARCHAR(25), OBJECT_NAME(@@PROCID))+ ‘
‘+
‘ErrorProcedure:’+ ERROR_PROCEDURE() +’
‘+
‘ErrorLine:’ + convert(varchar(7),ERROR_LINE()) +’
‘+
‘ErrorMessage:’ + ERROR_MESSAGE() +’


RAISERROR(@ErrorMessage,16,1)

END CATCH

END

GO


Missed Backups

October 17, 2011

Sometimes we all miss our failed job alerts it can lead to trouble though when you need to maintain compliance.

Here is a proc which will let you know if a database has not been backed up in more then X days.

/******************************************************************************************************
* Created By: MotherofAllGeeks
* Created on: 9/2011
* Purpose: Verify that Backups have been completed in X days
* exec proc_CheckLastBackupDate 1,’Mom@motherofallgeeks.com’, ‘MyMailProfle’
******************************************************************************************************/
CREATE PROCEDURE [dbo].[proc_CheckLastBackupDate]

@daystoCheck int,

@recipients varchar(255),
@profile varchar(255)
AS
BEGIN
SET
NOCOUNT
ON
BEGIN
 
 
 
TRY
 
/*Find out if a database has not been backed up for more then X days */
DECLARE @Database TABLE (DBName varchar(255), backupDiff int)
 
INSERTINTO @DatabaseSELECT A.name,datediff(dd,B.LastBackupDate,GETDATE()) DayDiffFROMsys.databases A 
 
INNERJOIN(SELECT a.database_name,max(convert(date,a.backup_finish_date )) LastBackupDateFROM msdb..backupset aINNERJOINmaster.sys.databases b on a.database_name = b.nameWHERE a.type='D'GROUPBY database_name)
 
B
on A.name = B.database_nameWHEREdatediff(dd,B.LastBackupDate,GETDATE())> @daystoCheck
 
IF (@@ROWCOUNT> 1)BEGIN
 
DECLARE @tableHTML NVARCHAR(MAX), @currentDate date, @usagepercentage int
 
SET @tableHTML =N'<Table border =1 cellpadding=5>'+N'<tr><th>DBname</th>'+N'<th>Last Backup</th>'+N'</tr>'+CAST(
( SELECT
td
=convert(varchar(30),database_name),'',
td
=convert(varchar(60),LastBackupDate),''
 
 
FROM (select database_name,max(a.backup_finish_date) LastBackupDatefrom msdb..backupset aINNERJOIN @Database n on A.database_name = n.DBNamewhere a.type='D'GROUPBY database_name)a
 
FORXMLPATH('tr'),TYPE)asNVARCHAR(max))+N'</table>'
 
declare @subject varchar(255)SELECT @subject ='The Following Databases May not have been backed Up on '+@@servernameexec msdb.dbo.sp_send_dbmail
@profile_name = @profile,
--'sqladmin',
 
-- @recipients = 'Maryanne_frake@adp.com',
@recipients
= @recipients,
@subject
= @subject,
@body
= @tableHTML,
@body_format
='HTML'
 
END
END
 
TRY
BEGIN
 
 
 
CATCH
 
DECLARE @ErrorMessage varchar(max)
 
 
SELECT @ErrorMessage ='ErrorNumber:'+convert(varchar(7),ERROR_NUMBER())+'<br>'+'ErrorSeverity:'+convert(varchar(7),ERROR_SEVERITY())+'<br>'+'ErrorState:'+convert(varchar(7),ERROR_STATE())+'<br>'+'Calling Procedure:'+CONVERT(VARCHAR(25),OBJECT_NAME(@@PROCID))+'<br>'+'ErrorProcedure:'+ERROR_PROCEDURE()+'<br>'+'ErrorLine:'+convert(varchar(7),ERROR_LINE())+'<br>'+'ErrorMessage:'+ERROR_MESSAGE()+'<br><hr>'RAISERROR(@ErrorMessage,16,1)
END
 
CATCH
 
 
END
 
GO
 
 

Long Running SQL Agent Jobs

October 14, 2011

Did you ever run into the situation where you had a job running into your production hours and you didn’t get a notification because the job didn’t actually fail?
I have experienced just that and here is a little script to get you a notification for a job which is running too long. Create this stored procedure in msdb then schedule it to run from SQL Server Agent. The Threshold for what is considered too long is a parameter. For me I check every two hours for a job which has been running longer then 60 minutes. Tailor it to work for your environment. Script was tested in SQL 2008 R1 Sp2

/************************************************************************************

– Proc Name : [[Proc_LongRunningJobs]]

– Description : This procedure will report Long Running SQL Agent Jobs

– Author : Mother of All Geeks

– exec [Proc_LongRunningJobs] 60,’MyMailProfile’, ‘mom@motherofallgeeks.com’

***********************************************************************************/

CREATE

PROCEDURE [dbo].[Proc_LongRunningJobs]

(

@Threshold int= 60

,

@MailProfile

varchar(100),

@recipients

varchar(255))

as

BEGIN

SET

NOCOUNT

ON

BEGIN

TRY

DECLARE

@Check varbinary (255

)

SELECTTOP 1 @Check = ja.job_idFROM msdb.dbo.sysjobactivity jaINNERJOIN sysjobs j on ja.job_id= j.job_idWHERE j.enabled=1 – and start_execution_date is not null and(stop_execution_date ISNULL)andDATEDIFF(MI,start_execution_date,GETDATE())isnotnulland(DATEDIFF(mi,start_execution_date,GETDATE())> @Threshold )and run_requested_date >CONVERT(date,getdate()-1)ORDERBY name – start_execution_date DESC

IF (@Check isnotnull)BEGINDECLARE @longRunning NVARCHAR(MAX)SET @longRunning =‘<Font><b>Long Running Jobs </b></font> <BR>’+N’<Table border =1 cellpadding=3>’+N’<th>SQLInstance</th>’+N’<th>JobName</th>’+N’<th>StartDateTime</th>’+N’<th>CurrentRunTimeinMin</th>’+N’</tr>’+CAST(

( SELECT

td

=isnull(@@SERVERNAME,),,

td

=isnull(name ,),,

td

=isnull(start_execution_date,),,

td

=isnull(DATEDIFF(MI,start_execution_date,GETDATE()),),FROM msdb.dbo.sysjobactivity jaINNERJOIN sysjobs j on ja.job_id= j.job_idWHERE j.enabled=1 – and start_execution_date is not null and(stop_execution_date ISNULL)andDATEDIFF(MI,start_execution_date,GETDATE())isnotnulland(DATEDIFF(mi,start_execution_date,GETDATE())> @Threshold )and run_requested_date >CONVERT(date,getdate()-1)and run_requested_date isnotnullORDERBY name – start_execution_date DESC

FORXMLPATH(‘tr’),TYPE)asNVARCHAR(max))+N’</table>’/*EMAIL THE ALERT*/

DECLARE @subject varchar(max), @body varchar(max)SET @subject =‘Long Running Job On: ‘+convert(varchar(25),@@servername)SET @body =isnull(@longRunning,)exec msdb..sp_send_dbmail@profile_name = @MailProfile, @recipients = @recipients, @subject = @subject, @body_format =‘HTML’, @body = @body,@query_result_header = 0END

END

TRY

BEGIN

CATCH

DECLARE @ErrorMessageCatch varchar(max)SELECT @ErrorMessageCatch =‘ErrorNumber:’+isnull(convert(varchar(7),ERROR_NUMBER()),‘ ‘)+‘ ErrorSeverity:’+isnull(convert(varchar(7),ERROR_SEVERITY()),‘ ‘)+‘ ErrorState:’+isnull(convert(varchar(7),ERROR_STATE()),‘ ‘)+‘ Calling Procedure:’+isnull(CONVERT(VARCHAR(25),OBJECT_NAME(@@PROCID)),‘ ‘)+‘ ErrorProcedure:’+isnull(ERROR_PROCEDURE(),‘ ‘)+‘ ErrorLine:’+isnull(convert(varchar(7),ERROR_LINE()),‘ ‘)+‘ ErrorMessage:’+isnull(ERROR_MESSAGE(),‘ ‘)

SELECT @ErrorMessageCatchRAISERROR(@ErrorMessageCatch,16,1)

END

CATCH

END

GO


Policy Evaluation Notifications

February 15, 2011

In SQL Server 2008 R1 a nice feature called Policies has been implemented. I like to use this feature to make sure no one is changing my database standards. You can create a policy to check for your standards then create the below stored proc and schedule it via a job to notify you of those policy failures.  Depending on how often your policies are evaluated you may have to change the date parameters in the query.
Enjoy!

use msdb

go
CREATE TYPE PolicyType AS TABLE
(PolicyName varchar(8000),
PolicyTarget varchar(8000),
ConditionName varchar(1000),
ConditionDesc varchar(1000)
)
GO
/******************************************************************************************************/
IF exists(SELECT 1 from sys.objects where name = ‘Get_Policy_Failure_Details’)
DROP PROCEDURE Get_Policy_Failure_Details
GO
/******************************************************************************************************
* Created By Mother of All Geeks
* Purpose is to provide more detailas about an evaluation failure in a policy
* Note A row is written to syspolicy_policy_execution_history_details only on exception
CREATE TYPE PolicyType AS TABLE
(PolicyName varchar(8000),
PolicyTarget varchar(8000),
ConditionName varchar(1000),
ConditionDesc varchar(1000)
)
SAMPLE EXEC CALL
DECLARE @FailedPolicies PolicyType
INSERT INTO @FailedPolicies
SELECT distinct Pol.name,
PolHistDet.target_query_expression,
cond.name,
cond.description –, PolHist.start_date,PolHist.end_date, PolHistDet.execution_date
FROM msdb.dbo.syspolicy_policies AS Pol
JOIN msdb.dbo.syspolicy_conditions AS Cond
ON Pol.condition_id = Cond.condition_id
JOIN msdb.dbo.syspolicy_policy_execution_history AS PolHist
ON Pol.policy_id = PolHist.policy_id
JOIN msdb.dbo.syspolicy_policy_execution_history_details AS PolHistDet
ON PolHist.history_id = PolHistDet.history_id
WHERE PolHistDet.result = 0
and PolHistDet.execution_date > convert(date,gETDATE())
and datediff(mi,PolHistDet.execution_date,GETDATE()) < 10
exec Get_Policy_Failure_Details ‘MOFG@motherofallgeeks.com’,MyMailProfile, @FailedPolicies
*******************************************************************************************************/

CREATE PROCEDURE Get_Policy_Failure_Details

(@TO varchar(255)
,@profile_name varchar(255)
,@FailedPolicies POLICYTYPE READONLY
)
AS

BEGIN
DECLARE @PolicyName varchar(60)
DECLARE @Target varchar(255)
DECLARE @execution_date datetime
DECLARE @histId int
DECLARE @detailHistId int
IF exists (SELECT 1 from @FailedPolicies)
– If there is a policy in failure
BEGIN
DECLARE @body varchar(max)
SELECT @body = ‘The Following Policy has failed evaluation:

SELECT @body = COALESCE(@body + ‘

  • ‘+
    PolicyName+ ‘ ‘+PolicyTarget +’ ‘ +’ ‘+ConditionName + ‘ ‘ +
    ConditionDesc , ‘
  • ‘)
    FROM @FailedPolicies

    exec msdb..sp_send_dbmail @profile_name = @profile_name
    , @recipients = @TO
    , @subject = ‘Policy Evaluation Failure’
    , @body_format = ‘HTML’
    , @body = @body

    END
    ELSE
    RETURN
    END


    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 querying 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]'

    Follow

    Get every new post delivered to your Inbox.