[SQL.Server.DMVs.实战].(SQL.Server.DMVs.in.Action).Ian.W.Stirk.文字版

遍历过程:

DECLARE @command1        NVARCHAR(2000),	--第一条运行的SQL指令
        @replacechar     NCHAR(1) = N'?',	--指定的占位符号
        @command2 NVARCHAR(2000) = NULL,	--第二条运行的SQL指令
        @command3        NVARCHAR(2000) = NULL,	--第三条运行的SQL指令
        @whereand        NVARCHAR(2000) = NULL,	--可选条件来选择表
        @precommand      NVARCHAR(2000) = NULL,	--执行指令前的操作(类似控件的触发前的操作)
        @postcommand     NVARCHAR(2000) = NULL --执行指令后的操作(类似 

SELECT @command1 = 'print ''?''',@replacechar = N'?',@command2 = NULL,@command3 
        = NULL,@whereand = NULL,@precommand = NULL,@postcommand = NULL
--打印所有数据库名
EXEC sp_msforeachdb 
        @command1        = @command1,
        @replacechar     = @replacechar,
        @command2        = @command2,
        @command3        = @command3,
   --   @whereand        = @whereand,
        @precommand      = @precommand,
        @postcommand     = @postcommand 
 --打印当前数据库中的表名
EXEC sp_msforeachtable 
		@command1        = @command1,
        @replacechar     = @replacechar,
        @command2        = @command2,
        @command3        = @command3,
        @whereand        = @whereand,
        @precommand      = @precommand,
        @postcommand     = @postcommand  

dmv 脚本:


----------------------------------------------------------------------------------------------------------- 
-- Code for dbo.dba_WhatSQLIsExecuting

CREATE PROC [dbo].[dba_WhatSQLIsExecuting]
AS
/*----------------------------------------------------------------------
 
Purpose: Shows what individual SQL statements are running.查看正在运行的语句

------------------------------------------------------------------------

Parameters: None.

Revision History:
 		12/08/2007	Ian_Stirk@yahoo.com Initial version

Example Usage:
	1. exec YourServerName.master.dbo.dba_WhatSQLIsExecuting			
 
-----------------------------------------------------------------------*/
BEGIN

	-- Do not lock anything, and do not get held up by any locks. 
	SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

	-- What SQL Statements Are Currently Running?
	SELECT [Spid] = session_Id
		,ecid
		, [Database] = DB_NAME(sp.dbid)
		, [User] = nt_username
		, [Status] = er.status
		, [Wait] = wait_type
		, [Individual Query] = SUBSTRING (qt.text, er.statement_start_offset/2, 
			 (CASE WHEN er.statement_end_offset = -1 
				THEN LEN(CONVERT(NVARCHAR(MAX), qt.text)) * 2 
			  ELSE er.statement_end_offset END - er.statement_start_offset)/2)
		,[Parent Query] = qt.text
		, Program = program_name
		, Hostname
		, nt_domain
		, start_time
	FROM sys.dm_exec_requests er --正在运行
	INNER JOIN sys.sysprocesses sp ON er.session_id = sp.spid
	CROSS APPLY sys.dm_exec_sql_text(er.sql_handle) as qt
	WHERE session_Id > 50			-- Ignore system spids. 
	AND session_Id NOT IN (@@SPID)	-- Ignore this current statement.
	ORDER BY 1, 2

END
GO


----------------------------------------------------------------------------------------------------------- 
-- Code for dbo.dba_BlockTracer


CREATE Function [dbo].[dba_GetSQLForSpid]
(
   @spid SMALLINT
)
RETURNS NVARCHAR(4000)
 

/*-------------------------------------------------
 

Purpose:   Returns the SQL text for a given spid.
 

---------------------------------------------------
 

Parameters:   @spid   - SQL Server process ID.
Returns:   @SqlText - SQL text for a given spid.
Revision History:
      01/12/2006   Ian_Stirk@yahoo.com Initial version
Example Usage:
   SELECT dbo.dba_GetSQLForSpid(51)
   SELECT dbo.dba_GetSQLForSpid(spid) AS [SQL text]
      , * FROM sys.sysprocesses WITH (NOLOCK) 
 

--------------------------------------------------*/
 

BEGIN
   DECLARE @SqlHandle BINARY(20)
   DECLARE @SqlText NVARCHAR(4000)
   -- Get sql_handle for the given spid.
   SELECT @SqlHandle = sql_handle 
      FROM sys.sysprocesses WITH (nolock) WHERE 
      spid = @spid
   -- Get the SQL text for the given sql_handle.
   SELECT @SqlText = [text] FROM 
      sys.dm_exec_sql_text(@SqlHandle)
   RETURN @SqlText
 

END
GO


CREATE PROC [dbo].[dba_BlockTracer]
AS
/*--------------------------------------------------
 
Purpose: Shows details of the root blocking process, together with details of any blocked processed
 

----------------------------------------------------
 

Parameters: None.
 

Revision History:
      19/07/2007   Ian_Stirk@yahoo.com Initial version
 

Example Usage:
   1. exec YourServerName.master.dbo.dba_BlockTracer
 

--------------------------------------------------*/
 

BEGIN
 

   -- Do not lock anything, and do not get held up by any locks. 
   SET TRANSACTION ISOLATION LEVEL READ 
      UNCOMMITTED
 

   -- If there are blocked processes...
   IF EXISTS(SELECT 1 FROM sys.sysprocesses WHERE 
      blocked != 0) 
   BEGIN
 

      -- Identify the root-blocking spid(s)
      SELECT  distinct t1.spid  AS [Root blocking spids]
         , t1.[loginame] AS [Owner]
         , master.dbo.dba_GetSQLForSpid(t1.spid) AS 
            'SQL Text' 
         , t1.[cpu]
         , t1.[physical_io]
         , DatabaseName = DB_NAME(t1.[dbid])
         , t1.[program_name]
         , t1.[hostname]
         , t1.[status]
         , t1.[cmd]
         , t1.[blocked]
         , t1.[ecid] 
      FROM  sys.sysprocesses t1, sys.sysprocesses t2
      WHERE t1.spid = t2.blocked
        AND t1.ecid = t2.ecid
        AND t1.blocked = 0 
      ORDER BY t1.spid, t1.ecid
 

      -- Identify the spids being blocked.
      SELECT t2.spid AS 'Blocked spid'
         , t2.blocked AS 'Blocked By'
         , t2.[loginame] AS [Owner]
         , master.dbo.dba_GetSQLForSpid(t2.spid) AS 
            'SQL Text' 
         , t2.[cpu]
         , t2.[physical_io]
         , DatabaseName = DB_NAME(t2.[dbid])
         , t2.[program_name]
         , t2.[hostname]
         , t2.[status]
         , t2.[cmd]
         , t2.ecid
      FROM sys.sysprocesses t1, sys.sysprocesses t2 
      WHERE t1.spid = t2.blocked
        AND t1.ecid = t2.ecid
      ORDER BY t2.blocked, t2.spid, t2.ecid
   END
 

   ELSE -- No blocked processes.
      PRINT 'No processes blocked.' 
 

END
GO



-------------------------------------------------------------------------------

-- Listing 1.1 A simple monitor

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

WAITFOR TIME '19:00:00'
GO

PRINT GETDATE()
EXEC master.dbo.dba_BlockTracer

IF @@ROWCOUNT > 0
BEGIN
	SELECT GETDATE() AS TIME
	EXEC master.dbo.dba_WhatSQLIsExecuting
END

WAITFOR DELAY '00:00:15'
GO  





-- Listing 1.2 Find your slowest queries

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

SELECT TOP 20
CAST(qs.total_elapsed_time / 1000000.0 AS DECIMAL(28, 2))
								AS [Total Elapsed Duration (s)]
, qs.execution_count
, SUBSTRING (qt.text,(qs.statement_start_offset/2) + 1,
((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) + 1) AS [Individual Query]
, qt.text AS [Parent Query]
, DB_NAME(qt.dbid) AS DatabaseName
, qp.query_plan
FROM sys.dm_exec_query_stats qs
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) qt
CROSS APPLY sys.dm_exec_query_plan(qs.plan_handle) qp
INNER JOIN sys.dm_exec_cached_plans cp
	ON qs.plan_handle=cp.plan_handle
ORDER BY total_elapsed_time DESC



-- Listing 1.3 Find those missing indexes

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

SELECT TOP 20
ROUND(s.avg_total_user_cost * s.avg_user_impact *
		(s.user_seeks + s.user_scans),0) AS [Total Cost]
, s.avg_user_impact
, d.statement AS TableName
, d.equality_columns
, d.inequality_columns
, d.included_columns
FROM sys.dm_db_missing_index_groups g
INNER JOIN sys.dm_db_missing_index_group_stats s
	ON s.group_handle = g.index_group_handle
INNER JOIN sys.dm_db_missing_index_details d
	ON d.index_handle = g.index_handle
ORDER BY [Total Cost] DESC



-- Listing 1.4 Identify what SQL is running now

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

SELECT er.session_Id AS [Spid]
, sp.ecid
, DB_NAME(sp.dbid) AS [Database]
, sp.nt_username
, er.status
, er.wait_type
, SUBSTRING (qt.text, (er.statement_start_offset/2) + 1,
((CASE WHEN er.statement_end_offset = -1
	THEN LEN(CONVERT(NVARCHAR(MAX), qt.text)) * 2
	ELSE er.statement_end_offset
END - er.statement_start_offset)/2) + 1) AS [Individual Query]
, qt.text AS [Parent Query]
, sp.program_name
, sp.Hostname
, sp.nt_domain
, er.start_time
FROM sys.dm_exec_requests er
INNER JOIN sys.sysprocesses sp ON er.session_id = sp.spid
CROSS APPLY sys.dm_exec_sql_text(er.sql_handle)as qt
WHERE session_Id > 50
AND session_Id NOT IN (@@SPID)
ORDER BY session_Id, ecid



-- Listing 1.5 Quickly find a cached plan

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

SELECT TOP 20
	st.text AS [SQL]
	, cp.cacheobjtype
	, cp.objtype
	, COALESCE(DB_NAME(st.dbid),
		DB_NAME(CAST(pa.value AS INT))+'*',
		'Resource') AS [DatabaseName]
	, cp.usecounts AS [Plan usage]
	, qp.query_plan
FROM sys.dm_exec_cached_plans cp
CROSS APPLY sys.dm_exec_sql_text(cp.plan_handle) st
CROSS APPLY sys.dm_exec_query_plan(cp.plan_handle) qp
OUTER APPLY sys.dm_exec_plan_attributes(cp.plan_handle) pa
WHERE pa.attribute = 'dbid'
AND st.text LIKE '%CREATE PROCEDURE%'




-- Listing 1.6 Missing index details

/*
Missing Index Details from ExecutionPlan1.sqlplan
The Query Processor estimates that implementing the following index could
improve the query cost by 67.4296%.
*/

/*
USE [YourDatabaseName]
GO
CREATE NONCLUSTERED INDEX [<Name of Missing Index, sysname,>]
ON [dbo].[PNLError] ([COB])
INCLUDE ([RequestId],[DealCode])
GO
*/





-- Listing 2.1 Restricting output to a given database

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

SELECT SUM(qs.total_logical_reads) AS [Total Reads]
		, SUM(qs.total_logical_writes) AS [Total Writes]
		, DB_NAME(qt.dbid) AS DatabaseName
FROM sys.dm_exec_query_stats qs
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) as qt
WHERE DB_NAME(qt.dbid) = 'apoms'
GROUP BY DB_NAME(qt.dbid)




-- Listing 2.2 Top 10 longest-running queries on server

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

SELECT TOP 10
	qs.total_elapsed_time AS [Total Time]
	, qs.execution_count AS [Execution count]
	, SUBSTRING (qt.text,(qs.statement_start_offset/2) + 1,
	((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) + 1) AS [Individual Query]
	, qt.text AS [Parent Query]
	, DB_NAME(qt.dbid) AS DatabaseName
	, qp.query_plan
FROM sys.dm_exec_query_stats qs
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) as qt
CROSS APPLY sys.dm_exec_query_plan(qs.plan_handle) qp
ORDER BY [Total Time] DESC;



-- Listing 2.3 Creating a temporary table WHERE 1 = 2

SELECT f.FactorId, f.FactorName, pf.PositionId
INTO #Temp01
FROM dbo.Factor f
INNER JOIN dbo.PositionFactor pf ON pf.FactorId = f.FactorId
WHERE 1 = 2



-- Listing 2.4 Looping over all databases on a server pattern

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

SELECT
	DB_NAME() AS DatabaseName
	, SCHEMA_NAME(o.Schema_ID) AS SchemaName
	, OBJECT_NAME(s.[object_id]) AS TableName
	, i.name AS IndexName
	, (s.user_seeks + s.user_scans + s.user_lookups) AS [Usage]
	, s.user_updates
	, i.fill_factor
INTO #TempUsage
FROM sys.dm_db_index_usage_stats s
INNER JOIN sys.indexes i ON s.[object_id] = i.[object_id]
AND s.index_id = i.index_id
INNER JOIN sys.objects o ON i.object_id = O.object_id
WHERE 1=2

EXEC sp_MSForEachDB 'USE [?];
INSERT INTO #TempUsage
SELECT TOP 10
	DB_NAME() AS DatabaseName
	, SCHEMA_NAME(o.Schema_ID) AS SchemaName
	, OBJECT_NAME(s.[object_id]) AS TableName
	, i.name AS IndexName
	, (s.user_seeks + s.user_scans + s.user_lookups) AS [Usage]
	, s.user_updates
	, i.fill_factor
FROM sys.dm_db_index_usage_stats s
INNER JOIN sys.indexes i ON s.[object_id] = i.[object_id]
	AND s.index_id = i.index_id
INNER JOIN sys.objects o ON i.object_id = O.object_id
WHERE s.database_id = DB_ID()
	AND i.name IS NOT NULL
	AND OBJECTPROPERTY(s.[object_id], ''IsMsShipped'') = 0
ORDER BY [Usage] DESC'

SELECT TOP 10 * FROM #TempUsage ORDER BY [Usage] DESC

DROP TABLE #TempUsage




-- Listing 2.5 Quickly find the most-used cached plans梥imple version

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

SELECT TOP 10
	st.text AS [SQL]
	, DB_NAME(st.dbid) AS DatabaseName
	, cp.usecounts AS [Plan usage]
	, qp.query_plan
FROM sys.dm_exec_cached_plans cp
CROSS APPLY sys.dm_exec_sql_text(cp.plan_handle) st
CROSS APPLY sys.dm_exec_query_plan(cp.plan_handle) qp
WHERE st.text LIKE '%CREATE PROCEDURE%'
ORDER BY cp.usecounts DESC




-- Listing 2.6 Extracting the Individual Query from the Parent Query

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

SELECT TOP 20
	qs.execution_count
	, SUBSTRING (qt.text, (qs.statement_start_offset/2) + 1,
	((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) + 1) AS [Individual Query]
	, qt.text AS [Parent Query]
	, DB_NAME(qt.dbid) AS DatabaseName
FROM sys.dm_exec_query_stats qs
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) as qt
ORDER BY execution_count DESC;



-- Listing 2.7 Identify the database of ad hoc queries and stored procedures

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

SELECT TOP 20
	st.text AS [SQL]
	,cp.cacheobjtype
	,cp.objtype
	, COALESCE(DB_NAME(st.dbid),
		DB_NAME(CAST(pa.value AS INT))+'*',
		'Resource') AS [DatabaseName]
	, cp.usecounts AS [Plan usage]
	, qp.query_plan
FROM sys.dm_exec_cached_plans cp
CROSS APPLY sys.dm_exec_sql_text(cp.plan_handle) st
CROSS APPLY sys.dm_exec_query_plan(cp.plan_handle) qp
OUTER APPLY sys.dm_exec_plan_attributes(cp.plan_handle) pa
WHERE pa.attribute = 'dbid'
ORDER BY cp.usecounts DESC;



-- Listing 2.8 Determine query effect via differential between snapshots

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

SELECT sql_handle, plan_handle, total_elapsed_time
, execution_count, statement_start_offset, statement_end_offset
INTO #PreWorkSnapShot
FROM sys.dm_exec_query_stats

EXEC dbo.IWSR
SELECT * FROM dbo.appdate

SELECT sql_handle, plan_handle, total_elapsed_time
, execution_count, statement_start_offset, statement_end_offset
INTO #PostWorkSnapShot
FROM sys.dm_exec_query_stats

SELECT
p2.total_elapsed_time - ISNULL(p1.total_elapsed_time, 0) AS [Duration]
, SUBSTRING (qt.text,p2.statement_start_offset/2 + 1,
((CASE WHEN p2.statement_end_offset = -1
THEN LEN(CONVERT(NVARCHAR(MAX), qt.text)) * 2
ELSE p2.statement_end_offset
END - p2.statement_start_offset)/2) + 1) AS [Individual Query]
, qt.text AS [Parent Query]
, DB_NAME(qt.dbid) AS DatabaseName
FROM #PreWorkSnapShot p1
RIGHT OUTER JOIN
#PostWorkSnapShot p2 ON p2.sql_handle = ISNULL(p1.sql_handle, p2.sql_handle)
	AND p2.plan_handle = ISNULL(p1.plan_handle, p2.plan_handle)
	AND p2.statement_start_offset = ISNULL(p1.statement_start_offset, p2.statement_start_offset)
	AND p2.statement_end_offset = ISNULL(p1.statement_end_offset, p2.statement_end_offset)
CROSS APPLY sys.dm_exec_sql_text(p2.sql_handle) as qt
WHERE p2.execution_count != ISNULL(p1.execution_count, 0)
ORDER BY [Duration] DESC

DROP TABLE #PreWorkSnapShot
DROP TABLE #PostWorkSnapShot




-- Listing 2.9 Example of building dynamic SQL

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

SELECT
TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME
INTO #TableDetails
FROM INFORMATION_SCHEMA.tables
WHERE TABLE_TYPE = 'BASE TABLE'

DECLARE @DynamicSQL NVARCHAR(MAX)
SET @DynamicSQL = ''

SELECT
	@DynamicSQL = @DynamicSQL + CHAR(10)
	+ ' SELECT COUNT_BIG(*) as [TableName: '
	+ TABLE_CATALOG + '.' + TABLE_SCHEMA + '. ' + TABLE_NAME
	+ + '] FROM ' + QUOTENAME(TABLE_CATALOG) + '.'
	+ QUOTENAME(TABLE_SCHEMA) + '. ' + QUOTENAME(TABLE_NAME)
FROM #TableDetails

EXECUTE sp_executesql @DynamicSQL

DROP TABLE #TableDetails



-- Listing 2.10 Example of printing the content of large variables

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

SELECT
TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME
INTO #TableDetails
FROM INFORMATION_SCHEMA.tables
WHERE TABLE_TYPE = 'BASE TABLE'

DECLARE @DynamicSQL NVARCHAR(MAX)
SET @DynamicSQL = ''

SELECT
	@DynamicSQL = @DynamicSQL + CHAR(10)
	+ ' SELECT COUNT_BIG(*) as [TableName: '
	+ TABLE_CATALOG + '.' + TABLE_SCHEMA + '. ' + TABLE_NAME
	+ + '] FROM ' + QUOTENAME(TABLE_CATALOG) + '.'
	+ QUOTENAME(TABLE_SCHEMA) + '. ' + QUOTENAME(TABLE_NAME)
FROM #TableDetails

--EXECUTE sp_executesql @DynamicSQL

DECLARE @StartOffset INT
DECLARE @Length INT
SET @StartOffset = 0
SET @Length = 4000

WHILE (@StartOffset < LEN(@DynamicSQL))
BEGIN
	PRINT SUBSTRING(@DynamicSQL, @StartOffset, @Length)
	SET @StartOffset = @StartOffset + @Length
END

PRINT SUBSTRING(@DynamicSQL, @StartOffset, @Length)

DROP TABLE #TableDetails




-- Listing 3.1 Identifying the most important missing indexes

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

SELECT TOP 20
	ROUND(s.avg_total_user_cost *
		s.avg_user_impact
		* (s.user_seeks + s.user_scans),0)
					AS [Total Cost]
	, d.[statement] AS [Table Name]
	, equality_columns
	, inequality_columns
	, included_columns
FROM sys.dm_db_missing_index_groups g
INNER JOIN sys.dm_db_missing_index_group_stats s
	ON s.group_handle = g.index_group_handle
INNER JOIN sys.dm_db_missing_index_details d
	ON d.index_handle = g.index_handle
ORDER BY [Total Cost] DESC



-- Listing 3.2 The most-costly unused indexes

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

SELECT
	DB_NAME() AS DatabaseName
	, SCHEMA_NAME(o.Schema_ID) AS SchemaName
	, OBJECT_NAME(s.[object_id]) AS TableName
	, i.name AS IndexName
	, s.user_updates
	, s.system_seeks + s.system_scans + s.system_lookups
								AS [System usage]
INTO #TempUnusedIndexes
FROM sys.dm_db_index_usage_stats s
INNER JOIN sys.indexes i ON s.[object_id] = i.[object_id]
AND s.index_id = i.index_id
INNER JOIN sys.objects o ON i.object_id = O.object_id
WHERE 1=2

EXEC sp_MSForEachDB 'USE [?];
INSERT INTO #TempUnusedIndexes
SELECT TOP 20
	DB_NAME() AS DatabaseName
	, SCHEMA_NAME(o.Schema_ID) AS SchemaName
	, OBJECT_NAME(s.[object_id]) AS TableName
	, i.name AS IndexName
	, s.user_updates
	, s.system_seeks + s.system_scans + s.system_lookups
							AS [System usage]
FROM sys.dm_db_index_usage_stats s
INNER JOIN sys.indexes i ON s.[object_id] = i.[object_id]
	AND s.index_id = i.index_id
INNER JOIN sys.objects o ON i.object_id = O.object_id
WHERE s.database_id = DB_ID()
	AND OBJECTPROPERTY(s.[object_id], ''IsMsShipped'') = 0
	AND s.user_seeks = 0
	AND s.user_scans = 0
	AND s.user_lookups = 0
	AND i.name IS NOT NULL
ORDER BY s.user_updates DESC'

SELECT TOP 20 * FROM #TempUnusedIndexes ORDER BY [user_updates] DESC

DROP TABLE #TempUnusedIndexes




-- Listing 3.3 The top high-maintenance indexes

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

SELECT
	DB_NAME() AS DatabaseName
	, SCHEMA_NAME(o.Schema_ID) AS SchemaName
	, OBJECT_NAME(s.[object_id]) AS TableName
	, i.name AS IndexName
	, (s.user_updates ) AS [update usage]
	, (s.user_seeks + s.user_scans + s.user_lookups)
									AS [Retrieval usage]
	, (s.user_updates) -
	  (s.user_seeks + s.user_scans + s.user_lookups) AS [Maintenance cost]
	, s.system_seeks + s.system_scans + s.system_lookups AS [System usage]
	, s.last_user_seek
	, s.last_user_scan
	, s.last_user_lookup
INTO #TempMaintenanceCost
FROM sys.dm_db_index_usage_stats s
INNER JOIN sys.indexes i ON s.[object_id] = i.[object_id]
AND s.index_id = i.index_id
INNER JOIN sys.objects o ON i.object_id = O.object_id
WHERE 1=2

EXEC sp_MSForEachDB 'USE [?];
INSERT INTO #TempMaintenanceCost
SELECT TOP 20
	DB_NAME() AS DatabaseName
	, SCHEMA_NAME(o.Schema_ID) AS SchemaName
	, OBJECT_NAME(s.[object_id]) AS TableName
	, i.name AS IndexName
	, (s.user_updates ) AS [update usage]
	, (s.user_seeks + s.user_scans + s.user_lookups)
								AS [Retrieval usage]
	, (s.user_updates) -
	(s.user_seeks + user_scans +
	s.user_lookups) AS [Maintenance cost]
	, s.system_seeks + s.system_scans + s.system_lookups AS [System usage]
	, s.last_user_seek
	, s.last_user_scan
	, s.last_user_lookup
FROM sys.dm_db_index_usage_stats s
INNER JOIN sys.indexes i ON s.[object_id] = i.[object_id]
	AND s.index_id = i.index_id
INNER JOIN sys.objects o ON i.object_id = O.object_id
WHERE s.database_id = DB_ID()
	AND i.name IS NOT NULL
	AND OBJECTPROPERTY(s.[object_id], ''IsMsShipped'') = 0
	AND (s.user_seeks + s.user_scans + s.user_lookups) > 0
ORDER BY [Maintenance cost] DESC'

SELECT top 20 * FROM #TempMaintenanceCost ORDER BY [Maintenance cost] DESC

DROP TABLE #TempMaintenanceCost




-- Listing 3.4 The most-used indexes

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
SELECT
	DB_NAME() AS DatabaseName
	, SCHEMA_NAME(o.Schema_ID) AS SchemaName
	, OBJECT_NAME(s.[object_id]) AS TableName
	, i.name AS IndexName
	, (s.user_seeks + s.user_scans + s.user_lookups) AS [Usage]
	, s.user_updates
	, i.fill_factor
INTO #TempUsage
FROM sys.dm_db_index_usage_stats s
INNER JOIN sys.indexes i ON s.[object_id] = i.[object_id]
	AND s.index_id = i.index_id
INNER JOIN sys.objects o ON i.object_id = O.object_id
WHERE 1=2

EXEC sp_MSForEachDB 'USE [?];
INSERT INTO #TempUsage
SELECT TOP 20
	DB_NAME() AS DatabaseName
	, SCHEMA_NAME(o.Schema_ID) AS SchemaName
	, OBJECT_NAME(s.[object_id]) AS TableName
	, i.name AS IndexName
	, (s.user_seeks + s.user_scans + s.user_lookups) AS [Usage]
	, s.user_updates
	, i.fill_factor
FROM sys.dm_db_index_usage_stats s
INNER JOIN sys.indexes i ON s.[object_id] = i.[object_id]
	AND s.index_id = i.index_id
INNER JOIN sys.objects o ON i.object_id = O.object_id
WHERE s.database_id = DB_ID()
	AND i.name IS NOT NULL
	AND OBJECTPROPERTY(s.[object_id], ''IsMsShipped'') = 0
ORDER BY [Usage] DESC'

SELECT TOP 20 * FROM #TempUsage ORDER BY [Usage] DESC

DROP TABLE #TempUsage




-- Listing 3.5 The most-fragmented indexes

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

SELECT
	DB_NAME() AS DatbaseName
	, SCHEMA_NAME(o.Schema_ID) AS SchemaName
	, OBJECT_NAME(s.[object_id]) AS TableName
	, i.name AS IndexName
	, ROUND(s.avg_fragmentation_in_percent,2) AS [Fragmentation %]
INTO #TempFragmentation
FROM sys.dm_db_index_physical_stats(db_id(),null, null, null, null) s
INNER JOIN sys.indexes i ON s.[object_id] = i.[object_id]
	AND s.index_id = i.index_id
INNER JOIN sys.objects o ON i.object_id = O.object_id
WHERE 1=2

EXEC sp_MSForEachDB 'USE [?];
INSERT INTO #TempFragmentation
SELECT TOP 20
	DB_NAME() AS DatbaseName
	, SCHEMA_NAME(o.Schema_ID) AS SchemaName
	, OBJECT_NAME(s.[object_id]) AS TableName
	, i.name AS IndexName
	, ROUND(s.avg_fragmentation_in_percent,2) AS [Fragmentation %]
FROM sys.dm_db_index_physical_stats(db_id(),null, null, null, null) s
INNER JOIN sys.indexes i ON s.[object_id] = i.[object_id]
	AND s.index_id = i.index_id
INNER JOIN sys.objects o ON i.object_id = O.object_id
WHERE s.database_id = DB_ID()
	AND i.name IS NOT NULL
	AND OBJECTPROPERTY(s.[object_id], ''IsMsShipped'') = 0
ORDER BY [Fragmentation %] DESC'

SELECT top 20 * FROM #TempFragmentation ORDER BY [Fragmentation %] DESC

DROP TABLE #TempFragmentation




-- Listing 3.6 Identifying indexes used by a given routine

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

SELECT
	SchemaName = ss.name
	, TableName = st.name
	, IndexName = ISNULL(si.name, '')
	, IndexType = si.type_desc
	, user_updates = ISNULL(ius.user_updates, 0)
	, user_seeks = ISNULL(ius.user_seeks, 0)
	, user_scans = ISNULL(ius.user_scans, 0)
	, user_lookups = ISNULL(ius.user_lookups, 0)
	, ssi.rowcnt
	, ssi.rowmodctr
	, si.fill_factor
INTO #IndexStatsPre
FROM sys.dm_db_index_usage_stats ius
RIGHT OUTER JOIN sys.indexes si ON ius.[object_id] = si.[object_id]
		AND ius.index_id = si.index_id
INNER JOIN sys.sysindexes ssi ON si.object_id = ssi.id
		AND si.name = ssi.name
INNER JOIN sys.tables st ON st.[object_id] = si.[object_id]
INNER JOIN sys.schemas ss ON ss.[schema_id] = st.[schema_id]
WHERE ius.database_id = DB_ID()
AND OBJECTPROPERTY(ius.[object_id], 'IsMsShipped') = 0

SELECT COB, COUNT(*) FROM dbo.request GROUP BY COB

SELECT
	SchemaName = ss.name
	, TableName = st.name
	, IndexName = ISNULL(si.name, '')
	, IndexType = si.type_desc
	, user_updates = ISNULL(ius.user_updates, 0)
	, user_seeks = ISNULL(ius.user_seeks, 0)
	, user_scans = ISNULL(ius.user_scans, 0)
	, user_lookups = ISNULL(ius.user_lookups, 0)
	, ssi.rowcnt
	, ssi.rowmodctr
	, si.fill_factor
INTO #IndexStatsPost
FROM sys.dm_db_index_usage_stats ius
RIGHT OUTER JOIN sys.indexes si ON ius.[object_id] = si.[object_id]
AND ius.index_id = si.index_id
INNER JOIN sys.sysindexes ssi ON si.object_id = ssi.id
AND si.name = ssi.name
INNER JOIN sys.tables st ON st.[object_id] = si.[object_id]
INNER JOIN sys.schemas ss ON ss.[schema_id] = st.[schema_id]
WHERE ius.database_id = DB_ID()
AND OBJECTPROPERTY(ius.[object_id], 'IsMsShipped') = 0

SELECT
	DB_NAME() AS DatabaseName
	, po.[SchemaName]
	, po.[TableName]
	, po.[IndexName]
	, po.[IndexType]
	, po.user_updates - ISNULL(pr.user_updates, 0) AS [User Updates]
	, po.user_seeks - ISNULL(pr.user_seeks, 0) AS [User Seeks]
	, po.user_scans - ISNULL(pr.user_scans, 0) AS [User Scans]
	, po.user_lookups - ISNULL(pr.user_lookups , 0) AS [User Lookups]
	, po.rowcnt - pr.rowcnt AS [Rows Inserted]
	, po.rowmodctr - pr.rowmodctr AS [Updates I/U/D]
	, po.fill_factor
FROM #IndexStatsPost po LEFT OUTER JOIN #IndexStatsPre pr
	ON pr.SchemaName = po.SchemaName
		AND pr.TableName = po.TableName
		AND pr.IndexName = po.IndexName
		AND pr.IndexType = po.IndexType
WHERE ISNULL(pr.user_updates, 0) != po.user_updates
	OR ISNULL(pr.user_seeks, 0) != po.user_seeks
	OR ISNULL(pr.user_scans, 0) != po.user_scans
	OR ISNULL(pr.user_lookups, 0) != po.user_lookups
ORDER BY po.[SchemaName], po.[TableName], po.[IndexName];

DROP TABLE #IndexStatsPre
DROP TABLE #IndexStatsPost






-- Listing 3.7 The databases with the most missing indexes

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

SELECT
	DB_NAME(database_id) AS DatabaseName
	, COUNT(*) AS [Missing Index Count]
FROM sys.dm_db_missing_index_details
GROUP BY DB_NAME(database_id)
ORDER BY [Missing Index Count] DESC





-- Listing 3.8 Indexes that aren抰 used at all

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

SELECT
	DB_NAME() AS DatbaseName
	, SCHEMA_NAME(O.Schema_ID) AS SchemaName
	, OBJECT_NAME(I.object_id) AS TableName
	, I.name AS IndexName
INTO #TempNeverUsedIndexes
FROM sys.indexes I INNER JOIN sys.objects O ON I.object_id = O.object_id
WHERE 1=2

EXEC sp_MSForEachDB 'USE [?];
INSERT INTO #TempNeverUsedIndexes
SELECT
	DB_NAME() AS DatbaseName
	, SCHEMA_NAME(O.Schema_ID) AS SchemaName
	, OBJECT_NAME(I.object_id) AS TableName
	, I.NAME AS IndexName
FROM sys.indexes I INNER JOIN sys.objects O ON I.object_id = O.object_id
LEFT OUTER JOIN sys.dm_db_index_usage_stats S ON S.object_id = I.object_id
	AND I.index_id = S.index_id
	AND DATABASE_ID = DB_ID()
WHERE OBJECTPROPERTY(O.object_id,''IsMsShipped'') = 0
	AND I.name IS NOT NULL
	AND S.object_id IS NULL'

SELECT * FROM #TempNeverUsedIndexes
ORDER BY DatbaseName, SchemaName, TableName, IndexName

DROP TABLE #TempNeverUsedIndexes



-- Listing 3.9 What is the state of your statistics?

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

SELECT
	ss.name AS SchemaName
	, st.name AS TableName
	, s.name AS IndexName
	, STATS_DATE(s.id,s.indid) AS 'Statistics Last Updated'
	, s.rowcnt AS 'Row Count'
	, s.rowmodctr AS 'Number Of Changes'
	, CAST((CAST(s.rowmodctr AS DECIMAL(28,8))/CAST(s.rowcnt AS
			DECIMAL(28,2)) * 100.0)
				AS DECIMAL(28,2)) AS '% Rows Changed'
FROM sys.sysindexes s
INNER JOIN sys.tables st ON st.[object_id] = s.[id]
INNER JOIN sys.schemas ss ON ss.[schema_id] = st.[schema_id]
WHERE s.id > 100
	AND s.indid > 0
	AND s.rowcnt >= 500
ORDER BY SchemaName, TableName, IndexName





-- Listing 4.1 How to find a cached plan

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

SELECT TOP 20
	st.text AS [SQL]
	, cp.cacheobjtype
	, cp.objtype
	, COALESCE(DB_NAME(st.dbid),
		DB_NAME(CAST(pa.value AS INT))+'*',
		'Resource') AS [DatabaseName]
	, cp.usecounts AS [Plan usage]
	, qp.query_plan
FROM sys.dm_exec_cached_plans cp
CROSS APPLY sys.dm_exec_sql_text(cp.plan_handle) st
CROSS APPLY sys.dm_exec_query_plan(cp.plan_handle) qp
OUTER APPLY sys.dm_exec_plan_attributes(cp.plan_handle) pa
WHERE pa.attribute = 'dbid'
AND st.text LIKE '%PartyType%'




-- Listing 4.2 Finding where a query is used

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

SELECT TOP 20
	SUBSTRING (qt.text,(qs.statement_start_offset/2) + 1,
	((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) + 1) AS [Individual Query]
, qt.text AS [Parent Query]
, DB_NAME(qt.dbid) AS DatabaseName
, qp.query_plan
FROM sys.dm_exec_query_stats qs
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) as qt
CROSS APPLY sys.dm_exec_query_plan(qs.plan_handle) qp
WHERE SUBSTRING (qt.text,(qs.statement_start_offset/2) + 1,
	((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) + 1)
LIKE '%insert into dbo.deal%'




-- Listing 4.3 The queries that take the longest time to run

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

SELECT TOP 20
CAST(qs.total_elapsed_time / 1000000.0 AS DECIMAL(28, 2))
	AS [Total Duration (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]
, qs.execution_count
, CAST(qs.total_elapsed_time / 1000000.0 / qs.execution_count
AS DECIMAL(28, 2))
AS [Average Duration (s)]
, SUBSTRING (qt.text,(qs.statement_start_offset/2) + 1,
	((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) + 1) AS [Individual Query]
, qt.text AS [Parent Query]
, DB_NAME(qt.dbid) AS DatabaseName
, qp.query_plan
FROM sys.dm_exec_query_stats qs
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) as qt
CROSS APPLY sys.dm_exec_query_plan(qs.plan_handle) qp
WHERE qs.total_elapsed_time > 0
ORDER BY qs.total_elapsed_time DESC




-- Listing 4.4 The queries spend the longest time being blocked

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

SELECT TOP 20
CAST((qs.total_elapsed_time - qs.total_worker_time) /
		1000000.0 AS DECIMAL(28,2)) AS [Total time blocked (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]
, qs.execution_count
, CAST((qs.total_elapsed_time - qs.total_worker_time) / 1000000.0
	/ qs.execution_count AS DECIMAL(28, 2)) AS [Blocking average (s)]
, SUBSTRING (qt.text,(qs.statement_start_offset/2) + 1,
	((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) + 1) AS [Individual Query]
, qt.text AS [Parent Query]
, DB_NAME(qt.dbid) AS DatabaseName
, qp.query_plan
FROM sys.dm_exec_query_stats qs
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) as qt
CROSS APPLY sys.dm_exec_query_plan(qs.plan_handle) qp
WHERE qs.total_elapsed_time > 0
ORDER BY [Total time blocked (s)] DESC





-- Listing 4.5 The queries that use the most CPU

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

SELECT TOP 20
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]
, qs.execution_count
, CAST((qs.total_worker_time) / 1000000.0
	/ qs.execution_count AS DECIMAL(28, 2)) AS [CPU time average (s)]
, SUBSTRING (qt.text,(qs.statement_start_offset/2) + 1,
((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) + 1) AS [Individual Query]
, qt.text AS [Parent Query]
, DB_NAME(qt.dbid) AS DatabaseName
, qp.query_plan
FROM sys.dm_exec_query_stats qs
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) as qt
CROSS APPLY sys.dm_exec_query_plan(qs.plan_handle) qp
WHERE qs.total_elapsed_time > 0
ORDER BY [Total CPU time (s)] DESC




-- Listing 4.6 The queries that use the most I/O

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

SELECT TOP 20
[Total IO] = (qs.total_logical_reads + qs.total_logical_writes)
, [Average IO] = (qs.total_logical_reads + qs.total_logical_writes) /
		qs.execution_count
, qs.execution_count
, SUBSTRING (qt.text,(qs.statement_start_offset/2) + 1,
	((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) + 1) AS [Individual Query]
, qt.text AS [Parent Query]
, DB_NAME(qt.dbid) AS DatabaseName
, qp.query_plan
FROM sys.dm_exec_query_stats qs
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) as qt
CROSS APPLY sys.dm_exec_query_plan(qs.plan_handle) qp
ORDER BY [Total IO] DESC





-- Listing 4.7 The queries that have been executed the most often

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

SELECT TOP 20
	qs.execution_count
	, SUBSTRING (qt.text,(qs.statement_start_offset/2) + 1,
	((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) + 1) AS [Individual Query]
	, qt.text AS [Parent Query]
	, DB_NAME(qt.dbid) AS DatabaseName
	, qp.query_plan
FROM sys.dm_exec_query_stats qs
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) as qt
CROSS APPLY sys.dm_exec_query_plan(qs.plan_handle) qp
ORDER BY qs.execution_count DESC;




-- Listing 4.8 Finding when a query was last run

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

SELECT DISTINCT TOP 20
	qs.last_execution_time
	, qt.text AS [Parent Query]
	, DB_NAME(qt.dbid) AS DatabaseName
FROM sys.dm_exec_query_stats qs
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) as qt
WHERE qt.text LIKE '%CREATE PROCEDURE%List%PickList%'
ORDER BY qs.last_execution_time DESC




-- Listing 4.9 Finding when a table was last inserted

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

SELECT TOP 20
	qs.last_execution_time
	, SUBSTRING (qt.text,(qs.statement_start_offset/2) + 1,
	((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) + 1) AS [Individual Query]
	, qt.text AS [Parent Query]
	, DB_NAME(qt.dbid) AS DatabaseName
FROM sys.dm_exec_query_stats qs
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) as qt
WHERE SUBSTRING (qt.text,(qs.statement_start_offset/2) + 1,
	((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) + 1)
LIKE '%INSERT INTO dbo.Underlying%'
ORDER BY qs.last_execution_time DESC






-- Listing 5.1 Finding queries with missing statistics

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

SELECT TOP 20
	st.text AS [Parent Query]
	, DB_NAME(st.dbid)AS [DatabaseName]
	, cp.usecounts AS [Usage Count]
	, qp.query_plan
FROM sys.dm_exec_cached_plans cp
CROSS APPLY sys.dm_exec_sql_text(cp.plan_handle) st
CROSS APPLY sys.dm_exec_query_plan(cp.plan_handle) qp
WHERE CAST(qp.query_plan AS NVARCHAR(MAX))
LIKE '%<ColumnsWithNoStatistics>%'
ORDER BY cp.usecounts DESC







-- Listing 5.2 Finding your default statistics options

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

SELECT name AS DatabaseName
	, is_auto_create_stats_on AS AutoCreateStatistics
	, is_auto_update_stats_on AS AutoUpdateStatistics
	, is_auto_update_stats_async_on	AS AutoUpdateStatisticsAsync
FROM sys.databases
ORDER BY DatabaseName




-- Listing 5.3 Finding disparate columns with different data types

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

SELECT
	COLUMN_NAME
	,[%] = CONVERT(DECIMAL(12,2),COUNT(COLUMN_NAME)*
			100.0 / COUNT(*)OVER())
INTO #Prevalence
FROM INFORMATION_SCHEMA.COLUMNS
GROUP BY COLUMN_NAME

SELECT DISTINCT
		C1.COLUMN_NAME
		, C1.TABLE_SCHEMA
		, C1.TABLE_NAME
		, C1.DATA_TYPE
		, C1.CHARACTER_MAXIMUM_LENGTH
		, C1.NUMERIC_PRECISION
		, C1.NUMERIC_SCALE
		, [%]
FROM INFORMATION_SCHEMA.COLUMNS C1
INNER JOIN INFORMATION_SCHEMA.COLUMNS C2 ON C1.COLUMN_NAME = C2.COLUMN_NAME
INNER JOIN #Prevalence p ON p.COLUMN_NAME = C1.COLUMN_NAME
WHERE ((C1.DATA_TYPE != C2.DATA_TYPE)
	OR (C1.CHARACTER_MAXIMUM_LENGTH != C2.CHARACTER_MAXIMUM_LENGTH)
	OR (C1.NUMERIC_PRECISION != C2.NUMERIC_PRECISION)
	OR (C1.NUMERIC_SCALE != C2.NUMERIC_SCALE))
ORDER BY [%] DESC, C1.COLUMN_NAME, C1.TABLE_SCHEMA, C1.TABLE_NAME

DROP TABLE #Prevalence






-- Listing 5.4 Finding queries that are running slower than normal

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

SELECT TOP 100
qs.execution_count AS [Runs]
, (qs.total_worker_time - qs.last_worker_time) / (qs.execution_count - 1) AS [Avg time]
, qs.last_worker_time AS [Last time]
, (qs.last_worker_time - ((qs.total_worker_time - qs.last_worker_time) /
(qs.execution_count - 1))) AS [Time Deviation]
, CASE WHEN qs.last_worker_time = 0
		THEN 100
	ELSE (qs.last_worker_time - ((qs.total_worker_time -
	qs.last_worker_time) / (qs.execution_count - 1))) * 100
	END
		/ (((qs.total_worker_time - qs.last_worker_time) /
(qs.execution_count - 1.0))) AS [% Time Deviation]
,qs.last_logical_reads + qs.last_logical_writes + qs.last_physical_reads AS [Last IO]
, ((qs.total_logical_reads + qs.total_logical_writes +
qs.total_physical_reads) -
(qs.last_logical_reads + last_logical_writes
+ qs.last_physical_reads))
/ (qs.execution_count - 1) AS [Avg IO]
, SUBSTRING (qt.text,(qs.statement_start_offset/2) + 1,
	((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) + 1) AS [Individual Query]
, qt.text AS [Parent Query]
, DB_NAME(qt.dbid) AS [DatabaseName]
INTO #SlowQueries
FROM sys.dm_exec_query_stats qs
CROSS APPLY sys.dm_exec_sql_text(qs.plan_handle) qt
WHERE qs.execution_count > 1
AND qs.total_worker_time != qs.last_worker_time
ORDER BY [% Time Deviation] DESC

SELECT TOP 100 [Runs]
	, [Avg time]
	, [Last time]
	, [Time Deviation]
	, [% Time Deviation]
	, [Last IO]
	, [Avg IO]
	, [Last IO] - [Avg IO] AS [IO Deviation]
	, CASE WHEN [Avg IO] = 0
			THEN 0
		ELSE ([Last IO]- [Avg IO]) * 100 / [Avg IO]
	  END AS [% IO Deviation]
	, [Individual Query]
	, [Parent Query]
	, [DatabaseName]
INTO #SlowQueriesByIO
FROM #SlowQueries
ORDER BY [% Time Deviation] DESC

SELECT TOP 100
	[Runs]
	, [Avg time]
	, [Last time]
	, [Time Deviation]
	, [% Time Deviation]
	, [Last IO]
	, [Avg IO]
	, [IO Deviation]
	, [% IO Deviation]
	, [Impedance] = [% Time Deviation] - [% IO Deviation]
	, [Individual Query]
	, [Parent Query]
	, [DatabaseName]
FROM #SlowQueriesByIO
WHERE [% Time Deviation] - [% IO Deviation] > 20
ORDER BY [Impedance] DESC

DROP TABLE #SlowQueries
DROP TABLE #SlowQueriesByIO





-- Listing 5.5 Finding unused stored procedures

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

SELECT s.name, s.type_desc
FROM sys.procedures s
LEFT OUTER JOIN sys.dm_exec_procedure_stats d
			ON s.object_id = d.object_id
WHERE d.object_id IS NULL
ORDER BY s.name




-- Listing 5.6 Which queries run over a given time period

--ThisRoutineIdentifier99

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

SELECT sql_handle, plan_handle, total_elapsed_time
, total_worker_time, total_logical_reads, total_logical_writes
, total_clr_time, execution_count, statement_start_offset
, statement_end_offset
INTO #PreWorkSnapShot
FROM sys.dm_exec_query_stats

WAITFOR DELAY '00:05:00'

SELECT sql_handle, plan_handle, total_elapsed_time
, total_worker_time, total_logical_reads, total_logical_writes
, total_clr_time, execution_count, statement_start_offset
, statement_end_offset
INTO #PostWorkSnapShot
FROM sys.dm_exec_query_stats

SELECT
p2.total_elapsed_time - ISNULL(p1.total_elapsed_time, 0) AS [Duration]
, p2.total_worker_time - ISNULL(p1.total_worker_time, 0) AS [Time on CPU]
, (p2.total_elapsed_time - ISNULL(p1.total_elapsed_time, 0)) -
(p2.total_worker_time - ISNULL(p1.total_worker_time, 0))
AS [Time blocked]
, p2.total_logical_reads - ISNULL(p1.total_logical_reads, 0) AS [Reads]
, p2.total_logical_writes - ISNULL(p1.total_logical_writes, 0) AS [Writes]
, p2.total_clr_time - ISNULL(p1.total_clr_time, 0) AS [CLR time]
, p2.execution_count - ISNULL(p1.execution_count, 0) AS [Executions]
, SUBSTRING (qt.text,p2.statement_start_offset/2 + 1,
		((CASE WHEN p2.statement_end_offset = -1
				THEN LEN(CONVERT(NVARCHAR(MAX), qt.text)) * 2
		ELSE p2.statement_end_offset
		END - p2.statement_start_offset)/2) + 1) AS [Individual Query]
, qt.text AS [Parent Query]
, DB_NAME(qt.dbid) AS DatabaseName
, qp.query_plan
FROM #PreWorkSnapShot p1
RIGHT OUTER JOIN
#PostWorkSnapShot p2 ON p2.sql_handle =
ISNULL(p1.sql_handle, p2.sql_handle)
AND p2.plan_handle = ISNULL(p1.plan_handle, p2.plan_handle)
AND p2.statement_start_offset =
ISNULL(p1.statement_start_offset, p2.statement_start_offset)
AND p2.statement_end_offset =
ISNULL(p1.statement_end_offset, p2.statement_end_offset)
CROSS APPLY sys.dm_exec_sql_text(p2.sql_handle) as qt
CROSS APPLY sys.dm_exec_query_plan(p2.plan_handle) qp
WHERE p2.execution_count != ISNULL(p1.execution_count, 0)
AND qt.text NOT LIKE '--ThisRoutineIdentifier99%'
ORDER BY [Duration] DESC

DROP TABLE #PreWorkSnapShot
DROP TABLE #PostWorkSnapShot





-- Listing 5.7 Amalgamated DMV snapshots

--ThisRoutineIdentifier

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

SELECT
	index_group_handle, index_handle
	, avg_total_user_cost, avg_user_impact, user_seeks, user_scans
INTO #PreWorkMissingIndexes
FROM sys.dm_db_missing_index_groups g
INNER JOIN sys.dm_db_missing_index_group_stats s
ON s.group_handle = g.index_group_handle

SELECT
	sql_handle, plan_handle, total_elapsed_time, total_worker_time
	, total_logical_reads, total_logical_writes, total_clr_time
	, execution_count, statement_start_offset, statement_end_offset
INTO #PreWorkQuerySnapShot
FROM sys.dm_exec_query_stats

SELECT
	[object_name], [counter_name], [instance_name]
	, [cntr_value], [cntr_type]
INTO #PreWorkOSSnapShot
FROM sys.dm_os_performance_counters

SELECT
	wait_type, waiting_tasks_count
	, wait_time_ms, max_wait_time_ms, signal_wait_time_ms
INTO #PreWorkWaitStats
FROM sys.dm_os_wait_stats

WAITFOR DELAY '00:05:00'

SELECT wait_type, waiting_tasks_count, wait_time_ms
	, max_wait_time_ms, signal_wait_time_ms
INTO #PostWorkWaitStats
FROM sys.dm_os_wait_stats

SELECT [object_name], [counter_name], [instance_name]
	, [cntr_value], [cntr_type]
INTO #PostWorkOSSnapShot
FROM sys.dm_os_performance_counters

SELECT sql_handle, plan_handle, total_elapsed_time, total_worker_time
	, total_logical_reads, total_logical_writes, total_clr_time
	, execution_count, statement_start_offset, statement_end_offset
INTO #PostWorkQuerySnapShot
FROM sys.dm_exec_query_stats

SELECT index_group_handle, index_handle
	, avg_total_user_cost, avg_user_impact, user_seeks, user_scans
INTO #PostWorkMissingIndexes
FROM sys.dm_db_missing_index_groups g
INNER JOIN sys.dm_db_missing_index_group_stats s
	ON s.group_handle = g.index_group_handle

SELECT
	p2.total_elapsed_time - ISNULL(p1.total_elapsed_time, 0) AS [Duration]
	, p2.total_worker_time - ISNULL(p1.total_worker_time, 0) AS [Time on CPU]
	, (p2.total_elapsed_time - ISNULL(p1.total_elapsed_time, 0)) -
	(p2.total_worker_time - ISNULL(p1.total_worker_time, 0))	AS [Time blocked]
	, p2.total_logical_reads - ISNULL(p1.total_logical_reads, 0) AS [Reads]
	, p2.total_logical_writes - ISNULL(p1.total_logical_writes, 0) AS [Writes]
	, p2.total_clr_time - ISNULL(p1.total_clr_time, 0) AS [CLR time]
	, p2.execution_count - ISNULL(p1.execution_count, 0) AS [Executions]
	, SUBSTRING (qt.text,p2.statement_start_offset/2 + 1,
	((CASE WHEN p2.statement_end_offset = -1
	THEN LEN(CONVERT(NVARCHAR(MAX), qt.text)) * 2
	ELSE p2.statement_end_offset
	END - p2.statement_start_offset)/2) + 1) AS [Individual Query]
	, qt.text AS [Parent Query]
	, DB_NAME(qt.dbid) AS DatabaseName
FROM #PreWorkQuerySnapShot p1
RIGHT OUTER JOIN
#PostWorkQuerySnapShot p2 ON p2.sql_handle =
ISNULL(p1.sql_handle, p2.sql_handle)
AND p2.plan_handle = ISNULL(p1.plan_handle, p2.plan_handle)
AND p2.statement_start_offset =
ISNULL(p1.statement_start_offset, p2.statement_start_offset)
AND p2.statement_end_offset =
ISNULL(p1.statement_end_offset, p2.statement_end_offset)
CROSS APPLY sys.dm_exec_sql_text(p2.sql_handle) as qt
WHERE p2.execution_count != ISNULL(p1.execution_count, 0)
AND qt.text NOT LIKE '--ThisRoutineIdentifier%'
ORDER BY [Duration] DESC

SELECT
	p2.wait_time_ms - ISNULL(p1.wait_time_ms, 0) AS wait_time_ms
	, p2.signal_wait_time_ms - ISNULL(p1.signal_wait_time_ms, 0)	AS signal_wait_time_ms
	, ((p2.wait_time_ms - ISNULL(p1.wait_time_ms, 0))
	- (p2.signal_wait_time_ms
	- ISNULL(p1.signal_wait_time_ms, 0))) AS RealWait
	, p2.wait_type
FROM #PreWorkWaitStats p1
RIGHT OUTER JOIN
#PostWorkWaitStats p2 ON p2.wait_type = ISNULL(p1.wait_type, p2.wait_type)
WHERE p2.wait_time_ms - ISNULL(p1.wait_time_ms, 0) > 0
AND p2.wait_type NOT LIKE '%SLEEP%'
AND p2.wait_type != 'WAITFOR'
ORDER BY RealWait DESC

SELECT
	ROUND((p2.avg_total_user_cost - ISNULL(p1.avg_total_user_cost, 0))
	* (p2.avg_user_impact - ISNULL(p1.avg_user_impact, 0)) *
	((p2.user_seeks - ISNULL(p1.user_seeks, 0))
	+ (p2.user_scans - ISNULL(p1.user_scans, 0))),0)	AS [Total Cost]
	, p2.avg_total_user_cost - ISNULL(p1.avg_total_user_cost, 0)	AS avg_total_user_cost
	, p2.avg_user_impact - ISNULL(p1.avg_user_impact, 0) AS avg_user_impact
	, p2.user_seeks - ISNULL(p1.user_seeks, 0) AS user_seeks
	, p2.user_scans - ISNULL(p1.user_scans, 0) AS user_scans
	, d.statement AS TableName
	, d.equality_columns
	, d.inequality_columns
	, d.included_columns
FROM #PreWorkMissingIndexes p1
RIGHT OUTER JOIN
#PostWorkMissingIndexes p2 ON p2.index_group_handle =
ISNULL(p1.index_group_handle, p2.index_group_handle)
AND p2.index_handle =
ISNULL(p1.index_handle, p2.index_handle)
INNER JOIN sys.dm_db_missing_index_details d
ON p2.index_handle = d.index_handle
WHERE p2.avg_total_user_cost - ISNULL(p1.avg_total_user_cost, 0) > 0
OR p2.avg_user_impact - ISNULL(p1.avg_user_impact, 0) > 0
OR p2.user_seeks - ISNULL(p1.user_seeks, 0) > 0
OR p2.user_scans - ISNULL(p1.user_scans, 0) > 0
ORDER BY [Total Cost] DESC

SELECT
	p2.object_name, p2.counter_name, p2.instance_name
	, ISNULL(p1.cntr_value, 0) AS InitialValue
	, p2.cntr_value AS FinalValue
	, p2.cntr_value - ISNULL(p1.cntr_value, 0) AS Change
	, (p2.cntr_value - ISNULL(p1.cntr_value, 0)) * 100 / p1.cntr_value AS [% Change]
FROM #PreWorkOSSnapShot p1
RIGHT OUTER JOIN
#PostWorkOSSnapShot p2 ON p2.object_name =
ISNULL(p1.object_name, p2.object_name)
AND p2.counter_name = ISNULL(p1.counter_name, p2.counter_name)
AND p2.instance_name = ISNULL(p1.instance_name, p2.instance_name)
WHERE p2.cntr_value - ISNULL(p1.cntr_value, 0) > 0
AND ISNULL(p1.cntr_value, 0) != 0
ORDER BY [% Change] DESC, Change DESC

DROP TABLE #PreWorkQuerySnapShot
DROP TABLE #PostWorkQuerySnapShot
DROP TABLE #PostWorkWaitStats
DROP TABLE #PreWorkWaitStats
DROP TABLE #PreWorkOSSnapShot
DROP TABLE #PostWorkOSSnapShot
DROP TABLE #PreWorkMissingIndexes
DROP TABLE #PostWorkMissingIndexes





-- Listing 5.8 What queries are running now

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

SELECT
es.session_id, es.host_name, es.login_name
, er.status, DB_NAME(database_id) AS DatabaseName
, SUBSTRING (qt.text,(er.statement_start_offset/2) + 1,
((CASE WHEN er.statement_end_offset = -1
	THEN LEN(CONVERT(NVARCHAR(MAX), qt.text)) * 2
	ELSE er.statement_end_offset
	END - er.statement_start_offset)/2) + 1) AS [Individual Query]
, qt.text AS [Parent Query]
, es.program_name, er.start_time, qp.query_plan
, er.wait_type, er.total_elapsed_time, er.cpu_time, er.logical_reads
, er.blocking_session_id, er.open_transaction_count, er.last_wait_type
, er.percent_complete
FROM sys.dm_exec_requests AS er
INNER JOIN sys.dm_exec_sessions AS es ON es.session_id = er.session_id
CROSS APPLY sys.dm_exec_sql_text( er.sql_handle) AS qt
CROSS APPLY sys.dm_exec_query_plan(er.plan_handle) qp
WHERE es.is_user_process=1
AND es.session_Id NOT IN (@@SPID)
ORDER BY es.session_id




-- Listing 5.9 Determining your most-recompiled queries

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

SELECT TOP 20
	qs.plan_generation_num
	, qs.total_elapsed_time
	, qs.execution_count
	, SUBSTRING (qt.text,(qs.statement_start_offset/2) + 1,
	((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) + 1) AS [Individual Query]
	, qt.text AS [Parent Query]
	, DB_NAME(qt.dbid)
	, qs.creation_time
	, qs.last_execution_time
FROM sys.dm_exec_query_stats qs
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) as qt
ORDER BY plan_generation_num DESC




-- Listing 6.1 Why are you waiting?

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

SELECT TOP 20
	wait_type, wait_time_ms, signal_wait_time_ms
	, wait_time_ms - signal_wait_time_ms AS RealWait
	, CONVERT(DECIMAL(12,2), wait_time_ms * 100.0 / SUM(wait_time_ms) OVER()) AS [% Waiting]
	, CONVERT(DECIMAL(12,2), (wait_time_ms - signal_wait_time_ms) * 100.0
		/ SUM(wait_time_ms) OVER()) AS [% RealWait]
FROM sys.dm_os_wait_stats
WHERE wait_type NOT LIKE '%SLEEP%'
AND wait_type != 'WAITFOR'
ORDER BY wait_time_ms DESC





-- Listing 6.2 Why are you waiting? (snapshot version)

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

SELECT wait_type, waiting_tasks_count
	, wait_time_ms, max_wait_time_ms, signal_wait_time_ms
INTO #PreWorkWaitStats
FROM sys.dm_os_wait_stats

WAITFOR DELAY '00:10:00'

SELECT wait_type, waiting_tasks_count
	, wait_time_ms, max_wait_time_ms, signal_wait_time_ms
INTO #PostWorkWaitStats
FROM sys.dm_os_wait_stats

SELECT
	p2.wait_time_ms - ISNULL(p1.wait_time_ms, 0) AS wait_time_ms
	, p2.signal_wait_time_ms - ISNULL(p1.signal_wait_time_ms, 0) AS signal_wait_time_ms
	, ((p2.wait_time_ms - ISNULL(p1.wait_time_ms, 0))
		- (p2.signal_wait_time_ms - ISNULL(p1.signal_wait_time_ms, 0))) AS RealWait
	, p2.wait_type
FROM #PreWorkWaitStats p1
RIGHT OUTER JOIN
#PostWorkWaitStats p2 ON p2.wait_type = ISNULL(p1.wait_type, p2.wait_type)
WHERE p2.wait_time_ms - ISNULL(p1.wait_time_ms, 0) > 0
AND p2.wait_type NOT LIKE '%SLEEP%'
AND p2.wait_type != 'WAITFOR'
ORDER BY RealWait DESC

DROP TABLE #PostWorkWaitStats
DROP TABLE #PreWorkWaitStats



-- Listing 6.3 Why your queries are waiting

--ThisRoutineIdentifier
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

SELECT
	sql_handle, plan_handle, total_elapsed_time, total_worker_time
	, total_logical_reads, total_logical_writes, total_clr_time
	, execution_count, statement_start_offset, statement_end_offset
INTO #PreWorkQuerySnapShot
FROM sys.dm_exec_query_stats

SELECT
	wait_type, waiting_tasks_count
	, wait_time_ms, max_wait_time_ms, signal_wait_time_ms
INTO #PreWorkWaitStats
FROM sys.dm_os_wait_stats

WAITFOR DELAY '00:05:00'

SELECT
	wait_type, waiting_tasks_count, wait_time_ms
	, max_wait_time_ms, signal_wait_time_ms
INTO #PostWorkWaitStats
FROM sys.dm_os_wait_stats

SELECT
	sql_handle, plan_handle, total_elapsed_time, total_worker_time
	, total_logical_reads, total_logical_writes, total_clr_time
	, execution_count, statement_start_offset, statement_end_offset
INTO #PostWorkQuerySnapShot
FROM sys.dm_exec_query_stats

SELECT
	p2.wait_time_ms - ISNULL(p1.wait_time_ms, 0) AS wait_time_ms
	, p2.signal_wait_time_ms - ISNULL(p1.signal_wait_time_ms, 0)	AS signal_wait_time_ms
	, ((p2.wait_time_ms - ISNULL(p1.wait_time_ms, 0))
	- (p2.signal_wait_time_ms - ISNULL(p1.signal_wait_time_ms, 0)))	AS RealWait
	, p2.wait_type
FROM #PreWorkWaitStats p1
RIGHT OUTER JOIN
#PostWorkWaitStats p2 ON p2.wait_type = ISNULL(p1.wait_type, p2.wait_type)
WHERE p2.wait_time_ms - ISNULL(p1.wait_time_ms, 0) > 0
	AND p2.wait_type NOT LIKE '%SLEEP%'
	AND p2.wait_type != 'WAITFOR'
ORDER BY RealWait DESC

SELECT
	p2.total_elapsed_time - ISNULL(p1.total_elapsed_time, 0) AS [Duration]
	, p2.total_worker_time - ISNULL(p1.total_worker_time, 0) AS [Time on CPU]
	, (p2.total_elapsed_time - ISNULL(p1.total_elapsed_time, 0)) -
	(p2.total_worker_time - ISNULL(p1.total_worker_time, 0))	AS [Time blocked]
	, p2.total_logical_reads - ISNULL(p1.total_logical_reads, 0) AS [Reads]
	, p2.total_logical_writes - ISNULL(p1.total_logical_writes, 0)	AS [Writes]
	, p2.total_clr_time - ISNULL(p1.total_clr_time, 0) AS [CLR time]
	, p2.execution_count - ISNULL(p1.execution_count, 0) AS [Executions]
	, SUBSTRING (qt.text,p2.statement_start_offset/2 + 1,
	((CASE WHEN p2.statement_end_offset = -1
	THEN LEN(CONVERT(NVARCHAR(MAX), qt.text)) * 2
	ELSE p2.statement_end_offset
	END - p2.statement_start_offset)/2) + 1) AS [Individual Query]
	, qt.text AS [Parent Query]
	, DB_NAME(qt.dbid) AS DatabaseName
FROM #PreWorkQuerySnapShot p1
RIGHT OUTER JOIN
#PostWorkQuerySnapShot p2 ON p2.sql_handle =
ISNULL(p1.sql_handle, p2.sql_handle)
AND p2.plan_handle = ISNULL(p1.plan_handle, p2.plan_handle)
AND p2.statement_start_offset =
ISNULL(p1.statement_start_offset, p2.statement_start_offset)
AND p2.statement_end_offset =
ISNULL(p1.statement_end_offset, p2.statement_end_offset)
CROSS APPLY sys.dm_exec_sql_text(p2.sql_handle) as qt
WHERE p2.execution_count != ISNULL(p1.execution_count, 0)
AND qt.text NOT LIKE '--ThisRoutineIdentifier%'
ORDER BY [Time blocked] DESC

DROP TABLE #PostWorkWaitStats
DROP TABLE #PreWorkWaitStats
DROP TABLE #PostWorkQuerySnapShot
DROP TABLE #PreWorkQuerySnapShot




-- Listing 6.4 What is blocked?

SELECT
	Blocking.session_id as BlockingSessionId
	, Sess.login_name AS BlockingUser
	, BlockingSQL.text AS BlockingSQL
	, Waits.wait_type WhyBlocked
	, Blocked.session_id AS BlockedSessionId
	, USER_NAME(Blocked.user_id) AS BlockedUser
	, BlockedSQL.text AS BlockedSQL
	, DB_NAME(Blocked.database_id) AS DatabaseName
FROM sys.dm_exec_connections AS Blocking
INNER JOIN sys.dm_exec_requests AS Blocked
	ON Blocking.session_id = Blocked.blocking_session_id
INNER JOIN sys.dm_os_waiting_tasks AS Waits
	ON Blocked.session_id = Waits.session_id
RIGHT OUTER JOIN sys.dm_exec_sessions Sess
	ON Blocking.session_id = sess.session_id
CROSS APPLY sys.dm_exec_sql_text(Blocking.most_recent_sql_handle) AS BlockingSQL
CROSS APPLY sys.dm_exec_sql_text(Blocked.sql_handle) AS BlockedSQL
ORDER BY BlockingSessionId, BlockedSessionId




-- Listing 6.5 Effect of queries on performance counters

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

SELECT
	[object_name], [counter_name], [instance_name]
	, [cntr_value], [cntr_type]
INTO #PreWorkOSSnapShot
FROM sys.dm_os_performance_counters

WAITFOR DELAY '00:05:00'

SELECT
	[object_name], [counter_name], [instance_name]
	, [cntr_value], [cntr_type]
INTO #PostWorkOSSnapShot
FROM sys.dm_os_performance_counters

SELECT
	p2.object_name, p2.counter_name, p2.instance_name
	, ISNULL(p1.cntr_value, 0) AS InitialValue
	, p2.cntr_value AS FinalValue
	, p2.cntr_value - ISNULL(p1.cntr_value, 0) AS Change
	, (p2.cntr_value - ISNULL(p1.cntr_value, 0)) * 100 / p1.cntr_value	AS [% Change]
FROM #PreWorkOSSnapShot p1
RIGHT OUTER JOIN
#PostWorkOSSnapShot p2 ON p2.object_name = ISNULL(p1.object_name, p2.object_name)
	AND p2.counter_name = ISNULL(p1.counter_name, p2.counter_name)
	AND p2.instance_name = ISNULL(p1.instance_name, p2.instance_name)
WHERE p2.cntr_value - ISNULL(p1.cntr_value, 0) > 0
	AND ISNULL(p1.cntr_value, 0) != 0
ORDER BY [% Change] DESC, Change DESC

DROP TABLE #PreWorkOSSnapShot
DROP TABLE #PostWorkOSSnapShot




-- Listing 6.6 Changes in performance counters and wait states

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

SELECT
	[object_name], [counter_name], [instance_name]
	, [cntr_value], [cntr_type]
INTO #PreWorkOSSnapShot
FROM sys.dm_os_performance_counters

SELECT
	wait_type, waiting_tasks_count
	, wait_time_ms, max_wait_time_ms, signal_wait_time_ms
INTO #PreWorkWaitStats
FROM sys.dm_os_wait_stats

WAITFOR DELAY '00:05:00'

SELECT
	wait_type, waiting_tasks_count, wait_time_ms
	, max_wait_time_ms, signal_wait_time_ms
INTO #PostWorkWaitStats
FROM sys.dm_os_wait_stats

SELECT
	[object_name], [counter_name], [instance_name]
	, [cntr_value], [cntr_type]
INTO #PostWorkOSSnapShot
FROM sys.dm_os_performance_counters

SELECT
	p2.wait_time_ms - ISNULL(p1.wait_time_ms, 0) AS wait_time_ms
	, p2.signal_wait_time_ms - ISNULL(p1.signal_wait_time_ms, 0) AS signal_wait_time_ms
	, ((p2.wait_time_ms - ISNULL(p1.wait_time_ms, 0)) -
	(p2.signal_wait_time_ms - ISNULL(p1.signal_wait_time_ms, 0))) AS RealWait
	, p2.wait_type
FROM #PreWorkWaitStats p1
RIGHT OUTER JOIN
#PostWorkWaitStats p2 ON p2.wait_type = ISNULL(p1.wait_type, p2.wait_type)
WHERE p2.wait_time_ms - ISNULL(p1.wait_time_ms, 0) > 0
	AND p2.wait_type NOT LIKE '%SLEEP%'
	AND p2.wait_type != 'WAITFOR'
ORDER BY RealWait DESC

SELECT
	p2.object_name, p2.counter_name, p2.instance_name
	, ISNULL(p1.cntr_value, 0) AS InitialValue
	, p2.cntr_value AS FinalValue
	, p2.cntr_value - ISNULL(p1.cntr_value, 0) AS Change
	, (p2.cntr_value - ISNULL(p1.cntr_value, 0)) * 100 / p1.cntr_value	AS [% Change]
FROM #PreWorkOSSnapShot p1
RIGHT OUTER JOIN
#PostWorkOSSnapShot p2 ON p2.object_name = ISNULL(p1.object_name, p2.object_name)
	AND p2.counter_name = ISNULL(p1.counter_name, p2.counter_name)
	AND p2.instance_name = ISNULL(p1.instance_name, p2.instance_name)
WHERE p2.cntr_value - ISNULL(p1.cntr_value, 0) > 0
	AND ISNULL(p1.cntr_value, 0) != 0
ORDER BY [% Change] DESC, Change DESC

DROP TABLE #PostWorkWaitStats
DROP TABLE #PreWorkWaitStats
DROP TABLE #PreWorkOSSnapShot
DROP TABLE #PostWorkOSSnapShot




-- Listing 6.7 Queries that change performance counters and wait states

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

SELECT
	sql_handle, plan_handle, total_elapsed_time, total_worker_time
	, total_logical_reads, total_logical_writes, total_clr_time
	, execution_count, statement_start_offset, statement_end_offset
INTO #PreWorkQuerySnapShot
FROM sys.dm_exec_query_stats

SELECT
	[object_name], [counter_name], [instance_name]
	, [cntr_value], [cntr_type]
INTO #PreWorkOSSnapShot
FROM sys.dm_os_performance_counters

SELECT
	wait_type, waiting_tasks_count
	, wait_time_ms, max_wait_time_ms, signal_wait_time_ms
INTO #PreWorkWaitStats
FROM sys.dm_os_wait_stats

WAITFOR DELAY '00:05:00'

SELECT
	wait_type, waiting_tasks_count, wait_time_ms
	, max_wait_time_ms, signal_wait_time_ms
INTO #PostWorkWaitStats
FROM sys.dm_os_wait_stats

SELECT
	[object_name], [counter_name], [instance_name]
	, [cntr_value], [cntr_type]
INTO #PostWorkOSSnapShot
FROM sys.dm_os_performance_counters

SELECT
	sql_handle, plan_handle, total_elapsed_time, total_worker_time
	, total_logical_reads, total_logical_writes, total_clr_time
	, execution_count, statement_start_offset, statement_end_offset
INTO #PostWorkQuerySnapShot
FROM sys.dm_exec_query_stats

SELECT
	p2.total_elapsed_time - ISNULL(p1.total_elapsed_time, 0) AS [Duration]
	, p2.total_worker_time - ISNULL(p1.total_worker_time, 0) AS [Time on CPU]
	, (p2.total_elapsed_time - ISNULL(p1.total_elapsed_time, 0)) -
	(p2.total_worker_time - ISNULL(p1.total_worker_time, 0)) AS [Time blocked]
	, p2.total_logical_reads - ISNULL(p1.total_logical_reads, 0) AS [Reads]
	, p2.total_logical_writes - ISNULL(p1.total_logical_writes, 0) AS [Writes]
	, p2.total_clr_time - ISNULL(p1.total_clr_time, 0) AS [CLR time]
	, p2.execution_count - ISNULL(p1.execution_count, 0) AS [Executions]
	, SUBSTRING (qt.text,p2.statement_start_offset/2 + 1,
	((CASE WHEN p2.statement_end_offset = -1
	THEN LEN(CONVERT(NVARCHAR(MAX), qt.text)) * 2
	ELSE p2.statement_end_offset
	END - p2.statement_start_offset)/2) + 1) AS [Individual Query]
	, qt.text AS [Parent Query]
	, DB_NAME(qt.dbid) AS DatabaseName
FROM #PreWorkQuerySnapShot p1
RIGHT OUTER JOIN
#PostWorkQuerySnapShot p2 ON p2.sql_handle = ISNULL(p1.sql_handle, p2.sql_handle)
	AND p2.plan_handle = ISNULL(p1.plan_handle, p2.plan_handle)
	AND p2.statement_start_offset =ISNULL(p1.statement_start_offset, p2.statement_start_offset)
	AND p2.statement_end_offset =ISNULL(p1.statement_end_offset, p2.statement_end_offset)
CROSS APPLY sys.dm_exec_sql_text(p2.sql_handle) as qt
WHERE p2.execution_count != ISNULL(p1.execution_count, 0)
AND qt.text NOT LIKE '--ThisRoutineIdentifier%'
ORDER BY [Duration] DESC

SELECT
	p2.wait_time_ms - ISNULL(p1.wait_time_ms, 0) AS wait_time_ms
	, p2.signal_wait_time_ms - ISNULL(p1.signal_wait_time_ms, 0) AS signal_wait_time_ms
	, ((p2.wait_time_ms - ISNULL(p1.wait_time_ms, 0)) -
	(p2.signal_wait_time_ms - ISNULL(p1.signal_wait_time_ms, 0))) AS RealWait
	, p2.wait_type
FROM #PreWorkWaitStats p1
RIGHT OUTER JOIN
#PostWorkWaitStats p2 ON p2.wait_type = ISNULL(p1.wait_type, p2.wait_type)
WHERE p2.wait_time_ms - ISNULL(p1.wait_time_ms, 0) > 0
	AND p2.wait_type NOT LIKE '%SLEEP%'
	AND p2.wait_type != 'WAITFOR'
ORDER BY RealWait DESC

SELECT
	p2.object_name, p2.counter_name, p2.instance_name
	, ISNULL(p1.cntr_value, 0) AS InitialValue
	, p2.cntr_value AS FinalValue
	, p2.cntr_value - ISNULL(p1.cntr_value, 0) AS Change
	, (p2.cntr_value - ISNULL(p1.cntr_value, 0)) * 100 / p1.cntr_value AS [% Change]
FROM #PreWorkOSSnapShot p1
RIGHT OUTER JOIN
#PostWorkOSSnapShot p2 ON p2.object_name = ISNULL(p1.object_name, p2.object_name)
	AND p2.counter_name = ISNULL(p1.counter_name, p2.counter_name)
	AND p2.instance_name = ISNULL(p1.instance_name, p2.instance_name)
WHERE p2.cntr_value - ISNULL(p1.cntr_value, 0) > 0
	AND ISNULL(p1.cntr_value, 0) != 0
ORDER BY [% Change] DESC, Change DESC

DROP TABLE #PreWorkQuerySnapShot
DROP TABLE #PostWorkQuerySnapShot
DROP TABLE #PostWorkWaitStats
DROP TABLE #PreWorkWaitStats
DROP TABLE #PreWorkOSSnapShot
DROP TABLE #PostWorkOSSnapShot






-- Listing 6.8 Recording DMV snapshots periodically

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

CREATE TABLE #PerfCounters
(	RunDateTime datetime NOT NULL,
	object_name nchar(128) NOT NULL,
	counter_name nchar(128) NOT NULL,
	instance_name nchar(128) NULL,
	cntr_value bigint NOT NULL,
	cntr_type int NOT NULL
)

ALTER TABLE #PerfCounters
ADD CONSTRAINT DF_PerFCounters_RunDateTime
DEFAULT (getdate()) FOR RunDateTime
GO

INSERT INTO #PerfCounters
		(object_name,counter_name,instance_name,cntr_value,cntr_type)
(SELECT object_name,counter_name,instance_name,cntr_value,cntr_type
FROM sys.dm_os_performance_counters)

WAITFOR DELAY '00:00:01'
GO 20

SELECT * FROM #PerfCounters
ORDER BY RunDateTime, object_name,counter_name,instance_name

DROP TABLE #PerfCounters





// Listing 7.1 C# code to create regular expression functionality for use within SQL Server
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;
using System.Text.RegularExpressions;
namespace CLRRegEx
{
    public partial class CLRRegEx
    {
        private const string sDigitsOnly = @"^\d+$";
        private const string sEmailRegEx =  @"^\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$";
        private const string sWebAddressRegEx =  @"^http(s)?://([\w-*]+\.)+[\w-*]+(/[\w- ./?%&=*]*)?$";
        [SqlFunction(IsDeterministic = true,
        DataAccess = DataAccessKind.None)]
        public static SqlBoolean RegExEmailIsValid(SqlString sSource)
        {
            if (sSource.IsNull)
                return SqlBoolean.Null;
            else
                return (SqlBoolean)Regex.IsMatch(sSource.Value, sEmailRegEx
                , RegexOptions.IgnoreCase);
        }
        [SqlFunction(IsDeterministic = true,
        DataAccess = DataAccessKind.None)]
        public static SqlBoolean RegExDigitsOnly(SqlString sSource)
        {
            if (sSource.IsNull)
                return SqlBoolean.Null;
            else
                return (SqlBoolean)Regex.IsMatch(sSource.Value, sDigitsOnly
                , RegexOptions.CultureInvariant);
        }
        [SqlFunction(IsDeterministic = true,
        DataAccess = DataAccessKind.None)]
        public static SqlBoolean WebAddressIsValid(SqlString sSource)
        {
            if (sSource.IsNull)
                return SqlBoolean.Null;
            else
                return (SqlBoolean)Regex.IsMatch(sSource.Value, sWebAddressRegEx
                , RegexOptions.IgnoreCase);
        }
        [SqlFunction(IsDeterministic = true,
        DataAccess = DataAccessKind.None)]
        public static SqlString RegExReplace(SqlString sSource, SqlString sPattern
        , SqlString sReplacement)
        {
            if (sSource.IsNull || sPattern.IsNull || sReplacement.IsNull)
                return SqlString.Null;
            else
                return (SqlString)Regex.Replace(sSource.Value, sPattern.Value
                , sReplacement.Value);
        }
        [SqlFunction(IsDeterministic = true,
        DataAccess = DataAccessKind.None)]
        public static SqlBoolean RegExMatch(SqlString sSource, SqlString sRegEx)
        {
            if (sSource.IsNull || sRegEx.IsNull)
                return SqlBoolean.Null;
            else
                return (SqlBoolean)Regex.IsMatch(sSource.Value, sRegEx.Value
                , RegexOptions.CultureInvariant);
        }
    };
}







-- Listing 7.2 Enabling CLR integration within SQL Server

EXEC sp_configure 'show advanced options', 1

RECONFIGURE

EXEC sp_configure 'clr_enabled', 1

RECONFIGURE





-- Listing 7.3 Using the CLR regular expression functionality


SELECT dbo.RegExDigitsOnly('123456');
SELECT dbo.RegExDigitsOnly('123456789abc');

SELECT dbo.RegExEmailIsValid('ian_stirk@yahoo.com');
SELECT dbo.RegExEmailIsValid('ian_stirk@yahoo');

SELECT dbo.WebAddressIsValid('http://www.manning.com/stirk');
SELECT dbo.WebAddressIsValid('http://wwwmanningcom');


SELECT dbo.RegExReplace('Q123AS456WE789', '[^0-9]', 'a');

SELECT dbo.RegExMatch('123456789', '^[0-9]+$');

SELECT dbo.RegExMatch('12345678abc9', '^[0-9]+$');



-- Listing 7.4 The queries that spend the most time in the CLR

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

SELECT TOP 20
	qs.total_clr_time
	, qs.total_elapsed_time AS [Duration]
	, qs.total_worker_time AS [Time on CPU]
	, qs.total_elapsed_time - qs.total_worker_time AS [Time waiting]
	, qs.total_logical_reads
	, qs.total_logical_writes
	, qs.execution_count
	, SUBSTRING (qt.text,qs.statement_start_offset/2 + 1,
	((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) + 1) AS [Individual Query]
	, qt.text AS [Parent Query]
	, DB_NAME(qt.dbid) AS DatabaseName
FROM sys.dm_exec_query_stats qs
CROSS APPLY sys.dm_exec_sql_text(sql_handle) as qt
WHERE qs.total_clr_time > 0
ORDER BY qs.total_clr_time DESC



-- Listing 7.5 The queries that spend the most time in the CLR (snapshot version)

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

SELECT
	sql_handle, plan_handle, total_elapsed_time, total_worker_time
	, total_logical_reads, total_logical_writes, total_clr_time
	, execution_count, statement_start_offset, statement_end_offset
INTO #PreWorkQuerySnapShot
FROM sys.dm_exec_query_stats

WAITFOR DELAY '00:10:00'

SELECT
	sql_handle, plan_handle, total_elapsed_time, total_worker_time
	, total_logical_reads, total_logical_writes, total_clr_time
	, execution_count, statement_start_offset, statement_end_offset
INTO #PostWorkQuerySnapShot
FROM sys.dm_exec_query_stats

SELECT
	p2.total_elapsed_time - ISNULL(p1.total_elapsed_time, 0) AS [Duration]
	, p2.total_worker_time - ISNULL(p1.total_worker_time, 0) AS [Time on CPU]
	, (p2.total_elapsed_time - ISNULL(p1.total_elapsed_time, 0)) -
	(p2.total_worker_time - ISNULL(p1.total_worker_time, 0)) AS [Time blocked]
	, p2.total_logical_reads - ISNULL(p1.total_logical_reads, 0) AS [Reads]
	, p2.total_logical_writes - ISNULL(p1.total_logical_writes, 0) AS [Writes]
	, p2.total_clr_time - ISNULL(p1.total_clr_time, 0) AS [CLR time]
	, p2.execution_count - ISNULL(p1.execution_count, 0) AS [Executions]
	, SUBSTRING (qt.text,p2.statement_start_offset/2 + 1,
	((CASE WHEN p2.statement_end_offset = -1
		THEN LEN(CONVERT(NVARCHAR(MAX), qt.text)) * 2
		ELSE p2.statement_end_offset
	END - p2.statement_start_offset)/2) + 1) AS [Individual Query]
	, qt.text AS [Parent Query]
	, DB_NAME(qt.dbid) AS DatabaseName
FROM #PreWorkQuerySnapShot p1
RIGHT OUTER JOIN
#PostWorkQuerySnapShot p2 ON p2.sql_handle =ISNULL(p1.sql_handle, p2.sql_handle)
	AND p2.plan_handle = ISNULL(p1.plan_handle, p2.plan_handle)
	AND p2.statement_start_offset =ISNULL(p1.statement_start_offset, p2.statement_start_offset)
	AND p2.statement_end_offset =ISNULL(p1.statement_end_offset, p2.statement_end_offset)
CROSS APPLY sys.dm_exec_sql_text(p2.sql_handle) as qt
WHERE p2.execution_count != ISNULL(p1.execution_count, 0)
	AND p2.total_clr_time - ISNULL(p1.total_clr_time, 0) <>0
ORDER BY [CLR time] DESC

DROP TABLE #PreWorkQuerySnapShot
DROP TABLE #PostWorkQuerySnapShot




-- Listing 7.6 Relationships between DMVs and CLR queries

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

SELECT
	g.index_group_handle, g.index_handle
	, s.avg_total_user_cost
	, s.avg_user_impact, s.user_seeks, s.user_scans
INTO #PreWorkMissingIndexes
FROM sys.dm_db_missing_index_groups g
INNER JOIN sys.dm_db_missing_index_group_stats s
	ON s.group_handle = g.index_group_handle

SELECT
	sql_handle, plan_handle, total_elapsed_time, total_worker_time
	, total_logical_reads, total_logical_writes, total_clr_time
	, execution_count, statement_start_offset, statement_end_offset
INTO #PreWorkQuerySnapShot
FROM sys.dm_exec_query_stats

SELECT
	[object_name], [counter_name], [instance_name]
	, [cntr_value], [cntr_type]
INTO #PreWorkOSSnapShot
FROM sys.dm_os_performance_counters

SELECT
	wait_type, waiting_tasks_count
	, wait_time_ms, max_wait_time_ms, signal_wait_time_ms
INTO #PreWorkWaitStats
FROM sys.dm_os_wait_stats

WAITFOR DELAY '00:10:00'

SELECT wait_type, waiting_tasks_count, wait_time_ms
	, max_wait_time_ms, signal_wait_time_ms
INTO #PostWorkWaitStats
FROM sys.dm_os_wait_stats

SELECT [object_name], [counter_name], [instance_name]
	, [cntr_value], [cntr_type]
INTO #PostWorkOSSnapShot
FROM sys.dm_os_performance_counters

SELECT sql_handle, plan_handle, total_elapsed_time, total_worker_time
	, total_logical_reads, total_logical_writes, total_clr_time
	, execution_count, statement_start_offset, statement_end_offset
INTO #PostWorkQuerySnapShot
FROM sys.dm_exec_query_stats

SELECT g.index_group_handle, g.index_handle, s.avg_total_user_cost
	, s.avg_user_impact, s.user_seeks, s.user_scans
INTO #PostWorkMissingIndexes
FROM sys.dm_db_missing_index_groups g
INNER JOIN sys.dm_db_missing_index_group_stats s
	ON s.group_handle = g.index_group_handle

SELECT
	p2.total_elapsed_time - ISNULL(p1.total_elapsed_time, 0) AS [Duration]
	, p2.total_worker_time - ISNULL(p1.total_worker_time, 0) AS [Time on CPU]
	, (p2.total_elapsed_time - ISNULL(p1.total_elapsed_time, 0)) -
	(p2.total_worker_time - ISNULL(p1.total_worker_time, 0)) AS [Time blocked]
	, p2.total_logical_reads - ISNULL(p1.total_logical_reads, 0) AS [Reads]
	, p2.total_logical_writes - ISNULL(p1.total_logical_writes, 0) AS [Writes]
	, p2.total_clr_time - ISNULL(p1.total_clr_time, 0) AS [CLR time]
	, p2.execution_count - ISNULL(p1.execution_count, 0) AS [Executions]
	, SUBSTRING (qt.text,p2.statement_start_offset/2 + 1,
	((CASE WHEN p2.statement_end_offset = -1
		THEN LEN(CONVERT(NVARCHAR(MAX), qt.text)) * 2
		ELSE p2.statement_end_offset
	END - p2.statement_start_offset)/2) + 1) AS [Individual Query]
	, qt.text AS [Parent Query]
	, DB_NAME(qt.dbid) AS DatabaseName
FROM #PreWorkQuerySnapShot p1
RIGHT OUTER JOIN
#PostWorkQuerySnapShot p2 ON p2.sql_handle =ISNULL(p1.sql_handle, p2.sql_handle)
	AND p2.plan_handle = ISNULL(p1.plan_handle, p2.plan_handle)
	AND p2.statement_start_offset =ISNULL(p1.statement_start_offset, p2.statement_start_offset)
	AND p2.statement_end_offset =ISNULL(p1.statement_end_offset, p2.statement_end_offset)
CROSS APPLY sys.dm_exec_sql_text(p2.sql_handle) as qt
WHERE p2.execution_count != ISNULL(p1.execution_count, 0)
	AND p2.total_clr_time - ISNULL(p1.total_clr_time, 0) <>0
ORDER BY [CLR time] DESC

SELECT
	p2.wait_time_ms - ISNULL(p1.wait_time_ms, 0) AS wait_time_ms
	, p2.signal_wait_time_ms - ISNULL(p1.signal_wait_time_ms, 0) AS signal_wait_time_ms
	, ((p2.wait_time_ms - ISNULL(p1.wait_time_ms, 0)) -
	(p2.signal_wait_time_ms	- ISNULL(p1.signal_wait_time_ms, 0))) AS RealWait
	, p2.wait_type
FROM #PreWorkWaitStats p1
RIGHT OUTER JOIN
#PostWorkWaitStats p2 ON p2.wait_type = ISNULL(p1.wait_type, p2.wait_type)
WHERE p2.wait_time_ms - ISNULL(p1.wait_time_ms, 0) > 0
	AND p2.wait_type NOT LIKE '%SLEEP%'
	AND p2.wait_type != 'WAITFOR'
ORDER BY RealWait DESC

SELECT
	ROUND((p2.avg_total_user_cost - ISNULL(p1.avg_total_user_cost, 0))
	* (p2.avg_user_impact - ISNULL(p1.avg_user_impact, 0)) *
	((p2.user_seeks - ISNULL(p1.user_seeks, 0)) + (p2.user_scans - ISNULL(p1.user_scans, 0))),0) AS [Total Cost]
	, p2.avg_total_user_cost - ISNULL(p1.avg_total_user_cost, 0) AS avg_total_user_cost
	, p2.avg_user_impact - ISNULL(p1.avg_user_impact, 0) AS avg_user_impact
	, p2.user_seeks - ISNULL(p1.user_seeks, 0) AS user_seeks
	, p2.user_scans - ISNULL(p1.user_scans, 0) AS user_scans
	, d.statement AS TableName
	, d.equality_columns
	, d.inequality_columns
	, d.included_columns
FROM #PreWorkMissingIndexes p1
RIGHT OUTER JOIN
#PostWorkMissingIndexes p2 ON p2.index_group_handle =ISNULL(p1.index_group_handle, p2.index_group_handle)
	AND p2.index_handle = ISNULL(p1.index_handle, p2.index_handle)
INNER JOIN sys.dm_db_missing_index_details d
	ON p2.index_handle = d.index_handle
WHERE p2.avg_total_user_cost - ISNULL(p1.avg_total_user_cost, 0) > 0
	OR p2.avg_user_impact - ISNULL(p1.avg_user_impact, 0) > 0
	OR p2.user_seeks - ISNULL(p1.user_seeks, 0) > 0
	OR p2.user_scans - ISNULL(p1.user_scans, 0) > 0
ORDER BY [Total Cost] DESC

SELECT
	p2.object_name, p2.counter_name, p2.instance_name
	, ISNULL(p1.cntr_value, 0) AS InitialValue
	, p2.cntr_value AS FinalValue
	, p2.cntr_value - ISNULL(p1.cntr_value, 0) AS Change
	, (p2.cntr_value - ISNULL(p1.cntr_value, 0)) * 100 / p1.cntr_value AS [% Change]
FROM #PreWorkOSSnapShot p1
RIGHT OUTER JOIN
#PostWorkOSSnapShot p2 ON p2.object_name =ISNULL(p1.object_name, p2.object_name)
	AND p2.counter_name = ISNULL(p1.counter_name, p2.counter_name)
	AND p2.instance_name = ISNULL(p1.instance_name, p2.instance_name)
WHERE p2.cntr_value - ISNULL(p1.cntr_value, 0) > 0
	AND ISNULL(p1.cntr_value, 0) != 0
ORDER BY [% Change] DESC, Change DESC

DROP TABLE #PreWorkQuerySnapShot
DROP TABLE #PostWorkQuerySnapShot
DROP TABLE #PostWorkWaitStats
DROP TABLE #PreWorkWaitStats
DROP TABLE #PreWorkOSSnapShot
DROP TABLE #PostWorkOSSnapShot
DROP TABLE #PreWorkMissingIndexes
DROP TABLE #PostWorkMissingIndexes





-- Listing 7.7 Obtaining information about SQL CLR assemblies


SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

SELECT
	DB_NAME(d.db_id) AS DatabaseName
	, USER_NAME(d.user_id) UserName
	, a.name AS AssemblyName
	, f.name AS AssemblyFileName
	, a.create_date AS AssemblyCreateDate
	, l.load_time AS AssemblyLoadDate
	, d.appdomain_name
	, d.creation_time AS AppDomainCreateTime
	, a.permission_set_desc
	, d.state
	, a.clr_name
	, a.is_visible
FROM sys.dm_clr_loaded_assemblies AS l
INNER JOIN sys.dm_clr_appdomains d
	ON l.appdomain_address = d.appdomain_address
INNER JOIN sys.assemblies AS a
	ON l.assembly_id = a.assembly_id
INNER JOIN sys.assembly_files AS f
	ON a.assembly_id = f.assembly_id
ORDER BY DatabaseName, UserName, AssemblyName





-- Listing 8.1 Transaction processing pattern

BEGIN TRY
	BEGIN TRAN
		SELECT 1/0
		PRINT 'Success'
	COMMIT
END TRY
BEGIN CATCH
	ROLLBACK
	PRINT 'An error has occurred'
END CATCH




-- Listing 8.2 Creating the sample database and table

CREATE DATABASE IWS_Temp
GO

USE IWS_Temp

CREATE TABLE [dbo].[tblCountry](
	[CountryId] [int] IDENTITY(1,1) NOT NULL,
	[Code] [char](3) NOT NULL,
	[Description] [varchar](50) NOT NULL)





-- Listing 8.3 Starting an open transaction

USE IWS_TEMP

BEGIN TRANSACTION

INSERT INTO [dbo].[tblCountry] ([Code], [Description])
VALUES('ENG', 'ENGLAND')





-- Listing 8.4 Selecting data from a table that has an open transaction against it

USE IWS_TEMP

SELECT * FROM [dbo].[tblCountry]








-- Listing 8.5 Observing the current locks

SELECT DB_NAME(resource_database_id) AS DatabaseName, request_session_id
	, resource_type, request_status, request_mode
FROM sys.dm_tran_locks
WHERE request_session_id !=@@spid
ORDER BY request_session_id






-- Listing 8.6 Template for handling deadlock retries

DECLARE @CurrentTry INT = 1
DECLARE @MaxRetries INT = 3
DECLARE @Complete BIT = 0

WHILE (@Complete = 0)
BEGIN
	BEGIN TRY
		EXEC dbo.SomeRoutine
		SET @Complete = 1
	END TRY
	BEGIN CATCH
		DECLARE @ErrorNum INT
		DECLARE @ErrorMessage NVARCHAR(4000)
		DECLARE @ErrorState INT
		DECLARE @ErrorSeverity INT
		
		SET @ErrorNum = ERROR_NUMBER()
		SET @ErrorMessage = ERROR_MESSAGE()
		SET @ErrorState = ERROR_STATE()
		SET @ErrorSeverity = ERROR_SEVERITY()
		
		IF (@ErrorNum = 1205) AND (@CurrentTry < @MaxRetries)
		BEGIN
			IF @@TRANCOUNT > 0
				ROLLBACK TRANSACTION
			SET @CurrentTry = @CurrentTry + 1
			WAITFOR DELAY '00:00:10'
		END
		ELSE
		BEGIN
			IF @@TRANCOUNT > 0
				ROLLBACK TRANSACTION
			SET @Complete = 1
			RAISERROR ('An error has occurred'
						, @ErrorSeverity
						, @ErrorState)
		END
	END CATCH
END





-- Listing 8.7 Information contained in sessions, connections, and requests

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

SELECT *
FROM sys.dm_exec_sessions s
LEFT OUTER JOIN sys.dm_exec_connections c
	ON s.session_id = c.session_id
LEFT OUTER JOIN sys.dm_exec_requests r
	ON c.connection_id = r.connection_id
WHERE s.session_id > 50





-- Listing 8.8 How to discover which locks are currently held

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

SELECT DB_NAME(resource_database_id) AS DatabaseName
	, request_session_id
	, resource_type
	, CASE
		WHEN resource_type = 'OBJECT'
		THEN OBJECT_NAME(resource_associated_entity_id)
		WHEN resource_type IN ('KEY', 'PAGE', 'RID')
		THEN (SELECT OBJECT_NAME(OBJECT_ID)
				FROM sys.partitions p
				WHERE p.hobt_id = l.resource_associated_entity_id)
	END AS resource_type_name
	, request_status
	, request_mode
FROM sys.dm_tran_locks l
WHERE request_session_id !=@@spid
ORDER BY request_session_id




-- Listing 8.9 How to identify contended resources

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

SELECT
	tl1.resource_type,
	DB_NAME(tl1.resource_database_id) AS DatabaseName,
	tl1.resource_associated_entity_id,
	tl1.request_session_id,
	tl1.request_mode,
	tl1.request_status
	, CASE
		WHEN tl1.resource_type = 'OBJECT'
			THEN OBJECT_NAME(tl1.resource_associated_entity_id)
		WHEN tl1.resource_type IN ('KEY', 'PAGE', 'RID')
			THEN (SELECT OBJECT_NAME(OBJECT_ID)
					FROM sys.partitions s
					WHERE s.hobt_id = tl1.resource_associated_entity_id)
	END AS resource_type_name
FROM sys.dm_tran_locks as tl1
INNER JOIN sys.dm_tran_locks as tl2
	ON tl1.resource_associated_entity_id = tl2.resource_associated_entity_id
		AND tl1.request_status <> tl2.request_status
		AND (tl1.resource_description = tl2.resource_description
	OR (tl1.resource_description IS NULL
	AND tl2.resource_description IS NULL))
ORDER BY tl1.resource_associated_entity_id, tl1.request_status




-- Listing 8.10 How to identify contended resources, including SQL query details

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

SELECT
	tl1.resource_type
	, DB_NAME(tl1.resource_database_id) AS DatabaseName
	, tl1.resource_associated_entity_id
	, tl1.request_session_id
	, tl1.request_mode
	, tl1.request_status
	, CASE
		WHEN tl1.resource_type = 'OBJECT'
			THEN OBJECT_NAME(tl1.resource_associated_entity_id)
		WHEN tl1.resource_type IN ('KEY', 'PAGE', 'RID')
			THEN (SELECT OBJECT_NAME(OBJECT_ID)
					FROM sys.partitions s
					WHERE s.hobt_id = tl1.resource_associated_entity_id)
	END AS resource_type_name
	, t.text AS [Parent Query]
	, SUBSTRING (t.text,(r.statement_start_offset/2) + 1,
		((CASE WHEN r.statement_end_offset = -1
		THEN LEN(CONVERT(NVARCHAR(MAX), t.text)) * 2
		ELSE r.statement_end_offset
		END - r.statement_start_offset)/2) + 1) AS [Individual Query]
FROM sys.dm_tran_locks as tl1
INNER JOIN sys.dm_tran_locks as tl2
	ON tl1.resource_associated_entity_id = tl2.resource_associated_entity_id
		AND tl1.request_status <> tl2.request_status
		AND (tl1.resource_description = tl2.resource_description
		OR (tl1.resource_description IS NULL
		AND tl2.resource_description IS NULL))
INNER JOIN sys.dm_exec_connections c
	ON tl1.request_session_id = c.most_recent_session_id
CROSS APPLY sys.dm_exec_sql_text(c.most_recent_sql_handle) t
LEFT OUTER JOIN sys.dm_exec_requests r ON c.connection_id = r.connection_id
ORDER BY tl1.resource_associated_entity_id, tl1.request_status





-- Listing 8.11 How to find an idle session with an open transaction

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

SELECT es.session_id, es.login_name, es.host_name, est.text
	, cn.last_read, cn.last_write, es.program_name
FROM sys.dm_exec_sessions es
INNER JOIN sys.dm_tran_session_transactions st
		ON es.session_id = st.session_id
INNER JOIN sys.dm_exec_connections cn
		ON es.session_id = cn.session_id
CROSS APPLY sys.dm_exec_sql_text(cn.most_recent_sql_handle) est
LEFT OUTER JOIN sys.dm_exec_requests er
		ON st.session_id = er.session_id
			AND er.session_id IS NULL
			





-- Listing 8.12 What抯 being blocked by idle sessions with open transactions

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

SELECT
	Waits.wait_duration_ms / 1000 AS WaitInSeconds
	, Blocking.session_id as BlockingSessionId
	, DB_NAME(Blocked.database_id) AS DatabaseName
	, Sess.login_name AS BlockingUser
	, Sess.host_name AS BlockingLocation
	, BlockingSQL.text AS BlockingSQL
	, Blocked.session_id AS BlockedSessionId
	, BlockedSess.login_name AS BlockedUser
	, BlockedSess.host_name AS BlockedLocation
	, BlockedSQL.text AS BlockedSQL
	, SUBSTRING (BlockedSQL.text, (BlockedReq.statement_start_offset/2) + 1,
	((CASE WHEN BlockedReq.statement_end_offset = -1
		THEN LEN(CONVERT(NVARCHAR(MAX), BlockedSQL.text)) * 2
		ELSE BlockedReq.statement_end_offset
		END - BlockedReq.statement_start_offset)/2) + 1)
					AS [Blocked Individual Query]
	, Waits.wait_type
FROM sys.dm_exec_connections AS Blocking
INNER JOIN sys.dm_exec_requests AS Blocked
	ON Blocking.session_id = Blocked.blocking_session_id
INNER JOIN sys.dm_exec_sessions Sess
	ON Blocking.session_id = sess.session_id
INNER JOIN sys.dm_tran_session_transactions st
	ON Blocking.session_id = st.session_id
LEFT OUTER JOIN sys.dm_exec_requests er
	ON st.session_id = er.session_id
		AND er.session_id IS NULL
INNER JOIN sys.dm_os_waiting_tasks AS Waits
	ON Blocked.session_id = Waits.session_id
CROSS APPLY sys.dm_exec_sql_text(Blocking.most_recent_sql_handle)AS BlockingSQL
INNER JOIN sys.dm_exec_requests AS BlockedReq
	ON Waits.session_id = BlockedReq.session_id
INNER JOIN sys.dm_exec_sessions AS BlockedSess
	ON Waits.session_id = BlockedSess.session_id
CROSS APPLY sys.dm_exec_sql_text(Blocked.sql_handle) AS BlockedSQL
ORDER BY WaitInSeconds





-- Listing 8.13 What抯 blocked by active sessions with open transactions

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

SELECT
	Waits.wait_duration_ms / 1000 AS WaitInSeconds
	, Blocking.session_id as BlockingSessionId
	, DB_NAME(Blocked.database_id) AS DatabaseName
	, Sess.login_name AS BlockingUser
	, Sess.host_name AS BlockingLocation
	, BlockingSQL.text AS BlockingSQL
	, Blocked.session_id AS BlockedSessionId
	, BlockedSess.login_name AS BlockedUser
	, BlockedSess.host_name AS BlockedLocation
	, BlockedSQL.text AS BlockedSQL
	, SUBSTRING (BlockedSQL.text, (BlockedReq.statement_start_offset/2) + 1,
	((CASE WHEN BlockedReq.statement_end_offset = -1
		THEN LEN(CONVERT(NVARCHAR(MAX), BlockedSQL.text)) * 2
		ELSE BlockedReq.statement_end_offset
		END - BlockedReq.statement_start_offset)/2) + 1)
								AS [Blocked Individual Query]
	, Waits.wait_type
FROM sys.dm_exec_connections AS Blocking
INNER JOIN sys.dm_exec_requests AS Blocked
	ON Blocking.session_id = Blocked.blocking_session_id
INNER JOIN sys.dm_exec_sessions Sess
	ON Blocking.session_id = sess.session_id
INNER JOIN sys.dm_tran_session_transactions st
	ON Blocking.session_id = st.session_id
INNER JOIN sys.dm_exec_requests er
	ON st.session_id = er.session_id
INNER JOIN sys.dm_os_waiting_tasks AS Waits
	ON Blocked.session_id = Waits.session_id
CROSS APPLY sys.dm_exec_sql_text(Blocking.most_recent_sql_handle) AS BlockingSQL
INNER JOIN sys.dm_exec_requests AS BlockedReq
	ON Waits.session_id = BlockedReq.session_id
INNER JOIN sys.dm_exec_sessions AS BlockedSess
	ON Waits.session_id = BlockedSess.session_id
CROSS APPLY sys.dm_exec_sql_text(Blocked.sql_handle) AS BlockedSQL
ORDER BY WaitInSeconds




-- Listing 8.14 What抯 blocked梐ctive and idle sessions with open transactions

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

SELECT
	Waits.wait_duration_ms / 1000 AS WaitInSeconds
	, Blocking.session_id as BlockingSessionId
	, DB_NAME(Blocked.database_id) AS DatabaseName
	, Sess.login_name AS BlockingUser
	, Sess.host_name AS BlockingLocation
	, BlockingSQL.text AS BlockingSQL
	, Blocked.session_id AS BlockedSessionId
	, BlockedSess.login_name AS BlockedUser
	, BlockedSess.host_name AS BlockedLocation
	, BlockedSQL.text AS BlockedSQL
	, SUBSTRING (BlockedSQL.text, (BlockedReq.statement_start_offset/2) + 1,
		((CASE WHEN BlockedReq.statement_end_offset = -1
		THEN LEN(CONVERT(NVARCHAR(MAX), BlockedSQL.text)) * 2
		ELSE BlockedReq.statement_end_offset
		END - BlockedReq.statement_start_offset)/2) + 1)
							AS [Blocked Individual Query]
	, Waits.wait_type
FROM sys.dm_exec_connections AS Blocking
INNER JOIN sys.dm_exec_requests AS Blocked
	ON Blocking.session_id = Blocked.blocking_session_id
INNER JOIN sys.dm_exec_sessions Sess
	ON Blocking.session_id = sess.session_id
INNER JOIN sys.dm_tran_session_transactions st
	ON Blocking.session_id = st.session_id
LEFT OUTER JOIN sys.dm_exec_requests er
	ON st.session_id = er.session_id
INNER JOIN sys.dm_os_waiting_tasks AS Waits
	ON Blocked.session_id = Waits.session_id
CROSS APPLY sys.dm_exec_sql_text(Blocking.most_recent_sql_handle) AS BlockingSQL
INNER JOIN sys.dm_exec_requests AS BlockedReq
	ON Waits.session_id = BlockedReq.session_id
INNER JOIN sys.dm_exec_sessions AS BlockedSess
	ON Waits.session_id = BlockedSess.session_id
CROSS APPLY sys.dm_exec_sql_text(Blocked.sql_handle) AS BlockedSQL
ORDER BY WaitInSeconds





-- Listing 8.15 What has been blocked for more than 30 seconds

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

SELECT
	Waits.wait_duration_ms / 1000 AS WaitInSeconds
	, Blocking.session_id as BlockingSessionId
	, Sess.login_name AS BlockingUser
	, Sess.host_name AS BlockingLocation
	, BlockingSQL.text AS BlockingSQL
	, Blocked.session_id AS BlockedSessionId
	, BlockedSess.login_name AS BlockedUser
	, BlockedSess.host_name AS BlockedLocation
	, BlockedSQL.text AS BlockedSQL
	, DB_NAME(Blocked.database_id) AS DatabaseName
FROM sys.dm_exec_connections AS Blocking
INNER JOIN sys.dm_exec_requests AS Blocked
	ON Blocking.session_id = Blocked.blocking_session_id
INNER JOIN sys.dm_exec_sessions Sess
	ON Blocking.session_id = sess.session_id
INNER JOIN sys.dm_tran_session_transactions st
	ON Blocking.session_id = st.session_id
LEFT OUTER JOIN sys.dm_exec_requests er
	ON st.session_id = er.session_id
		AND er.session_id IS NULL
INNER JOIN sys.dm_os_waiting_tasks AS Waits
	ON Blocked.session_id = Waits.session_id
CROSS APPLY sys.dm_exec_sql_text(Blocking.most_recent_sql_handle) AS BlockingSQL
INNER JOIN sys.dm_exec_requests AS BlockedReq
	ON Waits.session_id = BlockedReq.session_id
INNER JOIN sys.dm_exec_sessions AS BlockedSess
	ON Waits.session_id = BlockedSess.session_id
CROSS APPLY sys.dm_exec_sql_text(Blocked.sql_handle) AS BlockedSQL
WHERE Waits.wait_duration_ms > 30000
ORDER BY WaitInSeconds





-- Listing 9.1 Amount of space (total, used, and free) in tempdb

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

SELECT SUM(user_object_reserved_page_count
		+ internal_object_reserved_page_count
		+ version_store_reserved_page_count
		+ mixed_extent_page_count
		+ unallocated_extent_page_count) * (8.0/1024.0)
										AS [TotalSizeOfTempDB(MB)]
	, SUM(user_object_reserved_page_count
		+ internal_object_reserved_page_count
		+ version_store_reserved_page_count
		+ mixed_extent_page_count) * (8.0/1024.0)
										AS [UsedSpace (MB)]
	, SUM(unallocated_extent_page_count * (8.0/1024.0))
										AS [FreeSpace (MB)]
FROM sys.dm_db_file_space_usage






-- Listing 9.2 Total amount of space (data, log, and log used) by database

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

SELECT instance_name
	, counter_name
	, cntr_value / 1024.0 AS [Size(MB)]
FROM sys.dm_os_performance_counters
WHERE object_name = 'SQLServer:Databases'
AND counter_name IN ('Data File(s) Size (KB)'
					, 'Log File(s) Size (KB)'
					, 'Log File(s) Used Size (KB)')
ORDER BY instance_name, counter_name




-- Listing 9.3 Tempdb total space usage by object type

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

SELECT
	SUM (user_object_reserved_page_count) * (8.0/1024.0) AS [User Objects (MB)],
	SUM (internal_object_reserved_page_count) * (8.0/1024.0) AS [Internal Objects (MB)],
	SUM (version_store_reserved_page_count) * (8.0/1024.0) AS [Version Store (MB)],
	SUM (mixed_extent_page_count)* (8.0/1024.0) AS [Mixed Extent (MB)],
	SUM (unallocated_extent_page_count)* (8.0/1024.0) AS [Unallocated (MB)]
FROM sys.dm_db_file_space_usage





-- Listing 9.4 Space usage by session

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

SELECT es.session_id
	, ec.connection_id
	, es.login_name
	, es.host_name
	, st.text
	, su.user_objects_alloc_page_count
	, su.user_objects_dealloc_page_count
	, su.internal_objects_alloc_page_count
	, su.internal_objects_dealloc_page_count
	, ec.last_read
	, ec.last_write
	, es.program_name
FROM sys.dm_db_session_space_usage su
INNER JOIN sys.dm_exec_sessions es
	ON su.session_id = es.session_id
LEFT OUTER JOIN sys.dm_exec_connections ec
	ON su.session_id = ec.most_recent_session_id
OUTER APPLY sys.dm_exec_sql_text(ec.most_recent_sql_handle) st
WHERE su.session_id > 50





-- Listing 9.5 Space used and reclaimed in tempdb for completed batches

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

SELECT CAST(SUM(su.user_objects_alloc_page_count
	+ su.internal_objects_alloc_page_count) * (8.0/1024.0) AS DECIMAL(20,3)) AS [SpaceUsed(MB)]
	, CAST(SUM(su.user_objects_alloc_page_count
		- su.user_objects_dealloc_page_count
		+ su.internal_objects_alloc_page_count
		- su.internal_objects_dealloc_page_count)
		* (8.0/1024.0) AS DECIMAL(20,3)) AS [SpaceStillUsed(MB)]
	, su.session_id
	, ec.connection_id
	, es.login_name
	, es.host_name
	, st.text AS [LastQuery]
	, ec.last_read
	, ec.last_write
	, es.program_name
FROM sys.dm_db_session_space_usage su
INNER JOIN sys.dm_exec_sessions es ON su.session_id = es.session_id
LEFT OUTER JOIN sys.dm_exec_connections ec
	ON su.session_id = ec.most_recent_session_id
OUTER APPLY sys.dm_exec_sql_text(ec.most_recent_sql_handle) st
WHERE su.session_id > 50
GROUP BY su.session_id, ec.connection_id, es.login_name, es.host_name
		, st.text, ec.last_read, ec.last_write, es.program_name
ORDER BY [SpaceStillUsed(MB)] DESC




-- Listing 9.6 Space usage by task

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

SELECT es.session_id
	, ec.connection_id
	, es.login_name
	, es.host_name
	, st.text
	, tu.user_objects_alloc_page_count
	, tu.user_objects_dealloc_page_count
	, tu.internal_objects_alloc_page_count
	, tu.internal_objects_dealloc_page_count
	, ec.last_read
	, ec.last_write
	, es.program_name
FROM sys.dm_db_task_space_usage tu
INNER JOIN sys.dm_exec_sessions es ON tu.session_id = es.session_id
LEFT OUTER JOIN sys.dm_exec_connections ec
	ON tu.session_id = ec.most_recent_session_id
OUTER APPLY sys.dm_exec_sql_text(ec.most_recent_sql_handle) st
WHERE tu.session_id > 50





-- Listing 9.7 Space used and not reclaimed in tempdb for active batches

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

SELECT SUM(ts.user_objects_alloc_page_count
		+ ts.internal_objects_alloc_page_count)
		* (8.0/1024.0) AS [SpaceUsed(MB)]
		, SUM(ts.user_objects_alloc_page_count
		- ts.user_objects_dealloc_page_count
		+ ts.internal_objects_alloc_page_count
		- ts.internal_objects_dealloc_page_count)
		* (8.0/1024.0) AS [SpaceStillUsed(MB)]
	, ts.session_id
	, ec.connection_id
	, es.login_name
	, es.host_name
	, st.text AS [Parent Query]
	, SUBSTRING (st.text,(er.statement_start_offset/2) + 1,
		((CASE WHEN er.statement_end_offset = -1
		THEN LEN(CONVERT(NVARCHAR(MAX), st.text)) * 2
		ELSE er.statement_end_offset
		END - er.statement_start_offset)/2) + 1) AS [Current Query]
	, ec.last_read
	, ec.last_write
	, es.program_name
FROM sys.dm_db_task_space_usage ts
INNER JOIN sys.dm_exec_sessions es ON ts.session_id = es.session_id
LEFT OUTER JOIN sys.dm_exec_connections ec
	ON ts.session_id = ec.most_recent_session_id
OUTER APPLY sys.dm_exec_sql_text(ec.most_recent_sql_handle) st
LEFT OUTER JOIN sys.dm_exec_requests er ON ts.session_id = er.session_id
WHERE ts.session_id > 50
GROUP BY ts.session_id, ec.connection_id, es.login_name, es.host_name
	, st.text, ec.last_read, ec.last_write, es.program_name
	, SUBSTRING (st.text,(er.statement_start_offset/2) + 1,
	((CASE WHEN er.statement_end_offset = -1
	THEN LEN(CONVERT(NVARCHAR(MAX), st.text)) * 2
	ELSE er.statement_end_offset
	END - er.statement_start_offset)/2) + 1)
ORDER BY [SpaceStillUsed(MB)] DESC




-- Listing 9.8 Indexes under the most row-locking pressure

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

SELECT TOP 20
	x.name AS SchemaName
	, OBJECT_NAME(s.object_id) AS TableName
	, i.name AS IndexName
	, s.row_lock_wait_in_ms
	, s.row_lock_wait_count
FROM sys.dm_db_index_operational_stats(db_ID(), NULL, NULL, NULL) s
INNER JOIN sys.objects o ON s.object_id = o.object_id
INNER JOIN sys.indexes i ON s.index_id = i.index_id
	AND i.object_id = o.object_id
INNER JOIN sys.schemas x ON x.schema_id = o.schema_id
WHERE s.row_lock_wait_in_ms > 0
	AND o.is_ms_shipped = 0
ORDER BY s.row_lock_wait_in_ms DESC




-- Listing 9.9 Indexes with the most lock escalations

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

SELECT TOP 20
	x.name AS SchemaName
	, OBJECT_NAME (s.object_id) AS TableName
	, i.name AS IndexName
	, s.index_lock_promotion_count
FROM sys.dm_db_index_operational_stats(db_ID(), NULL, NULL, NULL) s
INNER JOIN sys.objects o ON s.object_id = o.object_id
INNER JOIN sys.indexes i ON s.index_id = i.index_id
							AND i.object_id = o.object_id
INNER JOIN sys.schemas x ON x.schema_id = o.schema_id
WHERE s.index_lock_promotion_count > 0
	AND o.is_ms_shipped = 0
ORDER BY s.index_lock_promotion_count DESC





-- Listing 9.10 Indexes with the most unsuccessful lock escalations

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

SELECT TOP 20
	x.name AS SchemaName
	, OBJECT_NAME (s.object_id) AS TableName
	, i.name AS IndexName
	, s.index_lock_promotion_attempt_count - s.index_lock_promotion_count AS UnsuccessfulIndexLockPromotions
FROM sys.dm_db_index_operational_stats(db_ID(), NULL, NULL, NULL) s
INNER JOIN sys.objects o ON s.object_id = o.object_id
INNER JOIN sys.indexes i ON s.index_id = i.index_id
	AND i.object_id = o.object_id
INNER JOIN sys.schemas x ON x.schema_id = o.schema_id
WHERE (s.index_lock_promotion_attempt_count - index_lock_promotion_count)>0
	AND o.is_ms_shipped = 0
ORDER BY UnsuccessfulIndexLockPromotions DESC




-- Listing 9.11 Indexes with the most page splits

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

SELECT TOP 20
	x.name AS SchemaName
	, object_name(s.object_id) AS TableName
	, i.name AS IndexName
	, s.leaf_allocation_count
	, s.nonleaf_allocation_count
FROM sys.dm_db_index_operational_stats(DB_ID(), NULL, NULL, NULL) s
INNER JOIN sys.objects o ON s.object_id = o.object_id
INNER JOIN sys.indexes i ON s.index_id = i.index_id
	AND i.object_id = o.object_id
INNER JOIN sys.schemas x ON x.schema_id = o.schema_id
WHERE s.leaf_allocation_count > 0
	AND o.is_ms_shipped = 0
ORDER BY s.leaf_allocation_count DESC



-- Listing 9.12 Indexes with the most latch contention

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

SELECT TOP 20
	x.name AS SchemaName
	, OBJECT_NAME(s.object_id) AS TableName
	, i.name AS IndexName
	, s.page_latch_wait_in_ms
	, s.page_latch_wait_count
FROM sys.dm_db_index_operational_stats(db_ID(), NULL, NULL, NULL) s
INNER JOIN sys.objects o ON s.object_id = o.object_id
INNER JOIN sys.indexes i ON s.index_id = i.index_id
	AND i.object_id = o.object_id
INNER JOIN sys.schemas x ON x.schema_id = o.schema_id
WHERE s.page_latch_wait_in_ms > 0
	AND o.is_ms_shipped = 0
ORDER BY s.page_latch_wait_in_ms DESC





-- Listing 9.13 Indexes with the most page I/O-latch contention

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

SELECT TOP 20
	x.name AS SchemaName
	, OBJECT_NAME(s.object_id) AS TableName
	, i.name AS IndexName
	, s.page_io_latch_wait_count
	, s.page_io_latch_wait_in_ms
FROM sys.dm_db_index_operational_stats(db_ID(), NULL, NULL, NULL) s
INNER JOIN sys.objects o ON s.object_id = o.object_id
INNER JOIN sys.indexes i ON s.index_id = i.index_id
	AND i.object_id = o.object_id
INNER JOIN sys.schemas x ON x.schema_id = o.schema_id
WHERE s.page_io_latch_wait_in_ms > 0
	AND o.is_ms_shipped = 0
ORDER BY s.page_io_latch_wait_in_ms DESC





-- Listing 9.14 Indexes under the most row-locking pressure梥napshot version

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

SELECT x.name AS SchemaName
	, OBJECT_NAME (s.object_id) AS TableName
	, i.name AS IndexName
	, s.row_lock_wait_in_ms
INTO #PreWorkIndexCount
FROM sys.dm_db_index_operational_stats(DB_ID(), NULL, NULL, NULL) s
INNER JOIN sys.objects o ON s.object_id = o.object_id
INNER JOIN sys.indexes i ON s.index_id = i.index_id
	AND i.object_id = o.object_id
INNER JOIN sys.schemas x ON x.schema_id = o.schema_id
WHERE s.row_lock_wait_in_ms > 0
	AND o.is_ms_shipped = 0

SELECT sql_handle, plan_handle, total_elapsed_time, total_worker_time
	, total_logical_reads, total_logical_writes, total_clr_time
	, execution_count, statement_start_offset, statement_end_offset
INTO #PreWorkQuerySnapShot
FROM sys.dm_exec_query_stats

WAITFOR DELAY '01:00:00'

SELECT x.name AS SchemaName
	, OBJECT_NAME (s.object_id) AS TableName
	, i.name AS IndexName
	, s.row_lock_wait_in_ms
INTO #PostWorkIndexCount
FROM sys.dm_db_index_operational_stats(DB_ID(), NULL, NULL, NULL) s
INNER JOIN sys.objects o ON s.object_id = o.object_id
INNER JOIN sys.indexes i ON s.index_id = i.index_id
	AND i.object_id = o.object_id
INNER JOIN sys.schemas x ON x.schema_id = o.schema_id
WHERE s.row_lock_wait_in_ms > 0
	AND o.is_ms_shipped = 0
	
SELECT sql_handle, plan_handle, total_elapsed_time, total_worker_time
	, total_logical_reads, total_logical_writes, total_clr_time
	, execution_count, statement_start_offset, statement_end_offset
INTO #PostWorkQuerySnapShot
FROM sys.dm_exec_query_stats

SELECT
	p2.SchemaName
	, p2.TableName
	, p2.IndexName
	, p2.row_lock_wait_in_ms - ISNULL(p1.row_lock_wait_in_ms, 0) AS RowLockWaitTimeDelta_ms
FROM #PreWorkIndexCount p1
RIGHT OUTER JOIN
#PostWorkIndexCount p2 ON p2.SchemaName =ISNULL(p1.SchemaName, p2.SchemaName)
	AND p2.TableName = ISNULL(p1.TableName, p2.TableName)
	AND p2.IndexName = ISNULL(p1.IndexName, p2.IndexName)
WHERE p2.row_lock_wait_in_ms - ISNULL(p1.row_lock_wait_in_ms, 0) > 0
ORDER BY RowLockWaitTimeDelta_ms DESC

SELECT
	p2.total_elapsed_time - ISNULL(p1.total_elapsed_time, 0) AS [Duration]
	, p2.total_worker_time - ISNULL(p1.total_worker_time, 0) AS [Time on CPU]
	, (p2.total_elapsed_time - ISNULL(p1.total_elapsed_time, 0)) -
	(p2.total_worker_time - ISNULL(p1.total_worker_time, 0)) AS [Time blocked]
	, p2.total_logical_reads - ISNULL(p1.total_logical_reads, 0) AS [Reads]
	, p2.total_logical_writes - ISNULL(p1.total_logical_writes, 0) AS [Writes]
	, p2.total_clr_time - ISNULL(p1.total_clr_time, 0) AS [CLR time]
	, p2.execution_count - ISNULL(p1.execution_count, 0) AS [Executions]
	, SUBSTRING (qt.text,p2.statement_start_offset/2 + 1,
		((CASE WHEN p2.statement_end_offset = -1
		THEN LEN(CONVERT(NVARCHAR(MAX), qt.text)) * 2
		ELSE p2.statement_end_offset
		END - p2.statement_start_offset)/2) + 1) AS [Individual Query]
	, qt.text AS [Parent Query]
	, DB_NAME(qt.dbid) AS DatabaseName
FROM #PreWorkQuerySnapShot p1
RIGHT OUTER JOIN
#PostWorkQuerySnapShot p2 ON p2.sql_handle = ISNULL(p1.sql_handle, p2.sql_handle)
	AND p2.plan_handle = ISNULL(p1.plan_handle, p2.plan_handle)
	AND p2.statement_start_offset =ISNULL(p1.statement_start_offset, p2.statement_start_offset)
	AND p2.statement_end_offset =ISNULL(p1.statement_end_offset, p2.statement_end_offset)
CROSS APPLY sys.dm_exec_sql_text(p2.sql_handle) as qt
WHERE p2.execution_count != ISNULL(p1.execution_count, 0)
	AND qt.text NOT LIKE '--ThisRoutineIdentifier%'
ORDER BY [Duration] DESC

DROP TABLE #PreWorkIndexCount
DROP TABLE #PostWorkIndexCount
DROP TABLE #PreWorkQuerySnapShot
DROP TABLE #PostWorkQuerySnapShot




-- Listing 9.15 Determining how many rows are inserted/deleted/updated/selected

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

SELECT
	sql_handle, plan_handle, total_elapsed_time, total_worker_time
	, total_logical_reads, total_logical_writes, total_clr_time
	, execution_count, statement_start_offset, statement_end_offset
INTO #PreWorkQuerySnapShot
FROM sys.dm_exec_query_stats

SELECT x.name AS SchemaName
	, OBJECT_NAME (s.object_id) AS TableName
	, i.name AS IndexName
	, s.leaf_delete_count
	, s.leaf_ghost_count
	, s.leaf_insert_count
	, s.leaf_update_count
	, s.range_scan_count
	, s.singleton_lookup_count
INTO #PreWorkIndexCount
FROM sys.dm_db_index_operational_stats(DB_ID(), NULL, NULL, NULL) s
INNER JOIN sys.objects o ON s.object_id = o.object_id
INNER JOIN sys.indexes i ON s.index_id = i.index_id
	AND i.object_id = o.object_id
INNER JOIN sys.schemas x ON x.schema_id = o.schema_id
WHERE o.is_ms_shipped = 0

WAITFOR DELAY '01:00:00'

SELECT
	sql_handle, plan_handle, total_elapsed_time, total_worker_time
	, total_logical_reads, total_logical_writes, total_clr_time
	, execution_count, statement_start_offset, statement_end_offset
INTO #PostWorkQuerySnapShot
FROM sys.dm_exec_query_stats

SELECT x.name AS SchemaName
	, OBJECT_NAME (s.object_id) AS TableName
	, i.name AS IndexName
	, s.leaf_delete_count
	, s.leaf_ghost_count
	, s.leaf_insert_count
	, s.leaf_update_count
	, s.range_scan_count
	, s.singleton_lookup_count
INTO #PostWorkIndexCount
FROM sys.dm_db_index_operational_stats(DB_ID(), NULL, NULL, NULL) s
INNER JOIN sys.objects o ON s.object_id = o.object_id
INNER JOIN sys.indexes i ON s.index_id = i.index_id
	AND i.object_id = o.object_id
INNER JOIN sys.schemas x ON x.schema_id = o.schema_id
WHERE o.is_ms_shipped = 0

SELECT
	p2.SchemaName
	, p2.TableName
	, p2.IndexName
	, p2.leaf_delete_count - ISNULL(p1.leaf_delete_count, 0) AS leaf_delete_countDelta
	, p2.leaf_ghost_count - ISNULL(p1.leaf_ghost_count, 0) AS leaf_ghost_countDelta
	, p2.leaf_insert_count - ISNULL(p1.leaf_insert_count, 0) AS leaf_insert_countDelta
	, p2.leaf_update_count - ISNULL(p1.leaf_update_count, 0) AS leaf_update_countDelta
	, p2.range_scan_count - ISNULL(p1.range_scan_count, 0) AS range_scan_countDelta
	, p2.singleton_lookup_count - ISNULL(p1.singleton_lookup_count, 0) AS singleton_lookup_countDelta
FROM #PreWorkIndexCount p1
RIGHT OUTER JOIN
#PostWorkIndexCount p2 ON p2.SchemaName =ISNULL(p1.SchemaName, p2.SchemaName)
	AND p2.TableName = ISNULL(p1.TableName, p2.TableName)
	AND p2.IndexName = ISNULL(p1.IndexName, p2.IndexName)
WHERE p2.leaf_delete_count - ISNULL(p1.leaf_delete_count, 0) > 0
	OR p2.leaf_ghost_count - ISNULL(p1.leaf_ghost_count, 0) > 0
	OR p2.leaf_insert_count - ISNULL(p1.leaf_insert_count, 0) > 0
	OR p2.leaf_update_count - ISNULL(p1.leaf_update_count, 0) > 0
	OR p2.range_scan_count - ISNULL(p1.range_scan_count, 0) > 0
	OR p2.singleton_lookup_count - ISNULL(p1.singleton_lookup_count, 0) > 0
ORDER BY leaf_delete_countDelta DESC

SELECT
	p2.total_elapsed_time - ISNULL(p1.total_elapsed_time, 0) AS [Duration]
	, p2.total_worker_time - ISNULL(p1.total_worker_time, 0) AS [Time on CPU]
	, (p2.total_elapsed_time - ISNULL(p1.total_elapsed_time, 0)) -
	(p2.total_worker_time - ISNULL(p1.total_worker_time, 0)) AS [Time blocked]
	, p2.total_logical_reads - ISNULL(p1.total_logical_reads, 0) AS [Reads]
	, p2.total_logical_writes - ISNULL(p1.total_logical_writes, 0) AS [Writes]
	, p2.total_clr_time - ISNULL(p1.total_clr_time, 0) AS [CLR time]
	, p2.execution_count - ISNULL(p1.execution_count, 0) AS [Executions]
	, SUBSTRING (qt.text,p2.statement_start_offset/2 + 1,
	((CASE WHEN p2.statement_end_offset = -1
		THEN LEN(CONVERT(NVARCHAR(MAX), qt.text)) * 2
		ELSE p2.statement_end_offset
	END - p2.statement_start_offset)/2) + 1) AS [Individual Query]
	, qt.text AS [Parent Query]
	, DB_NAME(qt.dbid) AS DatabaseName
FROM #PreWorkQuerySnapShot p1
RIGHT OUTER JOIN
#PostWorkQuerySnapShot p2 ON p2.sql_handle =ISNULL(p1.sql_handle, p2.sql_handle)
	AND p2.plan_handle = ISNULL(p1.plan_handle, p2.plan_handle)
	AND p2.statement_start_offset =ISNULL(p1.statement_start_offset, p2.statement_start_offset)
	AND p2.statement_end_offset =ISNULL(p1.statement_end_offset, p2.statement_end_offset)
CROSS APPLY sys.dm_exec_sql_text(p2.sql_handle) as qt
WHERE p2.execution_count != ISNULL(p1.execution_count, 0)
ORDER BY [Duration] DESC

DROP TABLE #PreWorkIndexCount
DROP TABLE #PostWorkIndexCount
DROP TABLE #PreWorkQuerySnapShot
DROP TABLE #PostWorkQuerySnapShot








// Listing 10.1 CLR function to extract the routine name

using System;
using Microsoft.SqlServer.Server;
public partial class UserDefinedFunctions
{
    [SqlFunction(IsDeterministic = true, DataAccess = DataAccessKind.None)]
    public static String ExtractSQLRoutineName(String sSource)
    {
        int _routineStartOffset;
        int _firstSpaceOffset;
        int _endOfRoutineNameOffset;
        if (String.IsNullOrEmpty(sSource) == true)
        {
            return null;
        }
        _routineStartOffset = sSource.IndexOf("CREATE PROC",
        StringComparison.CurrentCultureIgnoreCase);
        if (_routineStartOffset == -1)
        {
            _routineStartOffset = sSource.IndexOf("CREATE FUNC",
            StringComparison.CurrentCultureIgnoreCase);
        }
        if (_routineStartOffset == -1)
        {
            return null;
        }
        _routineStartOffset = _routineStartOffset + "CREATE FUNC".Length;
        _firstSpaceOffset = sSource.IndexOf(" ", _routineStartOffset);
        for (int i = _firstSpaceOffset; i < (sSource.Length - 1); i++)
        {
            if (sSource.Substring(i, 1) != " ")
            {
                _firstSpaceOffset = i;
                break;
            }
        }
        _endOfRoutineNameOffset = sSource.IndexOfAny(new char[] { ' ',
'(', '\t', '\r', '\n' }, _firstSpaceOffset + 1);
        if (_endOfRoutineNameOffset > _routineStartOffset)
        {
            return sSource.Substring(_firstSpaceOffset,
            (_endOfRoutineNameOffset - _firstSpaceOffset));
        }
        else
            return null;
    }
};






-- Listing 10.2 Recompile routines that are running slower than normal

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

SELECT TOP 100
	qs.execution_count AS [Runs]
	, (qs.total_worker_time - qs.last_worker_time) /
	(qs.execution_count - 1) AS [Avg time]
	, qs.last_worker_time AS [Last time]
	, (qs.last_worker_time - ((qs.total_worker_time - qs.last_worker_time)
	/ (qs.execution_count - 1))) AS [Time Deviation]
	, CASE WHEN qs.last_worker_time = 0
			THEN 100
		ELSE (qs.last_worker_time - ((qs.total_worker_time -
			qs.last_worker_time) / (qs.execution_count - 1))) * 100
		END
			/ (((qs.total_worker_time - qs.last_worker_time)
			/ (qs.execution_count - 1))) AS [% Time Deviation]
	, qs.last_logical_reads + qs.last_logical_writes
			+ qs.last_physical_reads AS [Last IO]
	, ((qs.total_logical_reads + qs.total_logical_writes +
			qs.total_physical_reads) - (qs.last_logical_reads +
			qs.last_logical_writes + qs.last_physical_reads))
			/ (qs.execution_count - 1) AS [Avg IO]
	, SUBSTRING (qt.text,(qs.statement_start_offset/2) + 1,
		((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) + 1) AS [Individual Query]
	, qt.text AS [Parent Query]
	, DB_NAME(qt.dbid) AS [DatabaseName]
INTO #SlowQueries
FROM sys.dm_exec_query_stats qs
CROSS APPLY sys.dm_exec_sql_text(qs.plan_handle) qt
WHERE qs.execution_count > 1
	AND qs.total_worker_time != qs.last_worker_time
ORDER BY [% Time Deviation] DESC

SELECT TOP 100 [Runs]
	, [Avg time]
	, [Last time]
	, [Time Deviation]
	, [% Time Deviation]
	, [Last IO]
	, [Avg IO]
	, [Last IO] - [Avg IO] AS [IO Deviation]
	, CASE WHEN [Avg IO] = 0
		THEN 0
		ELSE ([Last IO]- [Avg IO]) * 100 / [Avg IO]
		END AS [% IO Deviation]
	, [Individual Query]
	, [Parent Query]
	, [DatabaseName]
INTO #SlowQueriesByIO
FROM #SlowQueries
ORDER BY [% Time Deviation] DESC

SELECT TOP 100
	[Runs]
	, [Avg time]
	, [Last time]
	, [Time Deviation]
	, [% Time Deviation]
	, [Last IO]
	, [Avg IO]
	, [IO Deviation]
	, [% IO Deviation]
	, [Impedance] = [% Time Deviation] - [% IO Deviation]
	, [Individual Query]
	, [Parent Query]
	, [DatabaseName]
INTO #QueriesRunningSlowerThanNormal
FROM #SlowQueriesByIO
WHERE [% Time Deviation] - [% IO Deviation] > 20
ORDER BY [Impedance] DESC

SELECT DISTINCT
	' EXEC sp_recompile ' + '''' + '[' + [DatabaseName] + '].'
	+ dbo.ExtractSQLRoutineName([Parent Query]) + '''' AS recompileRoutineSQL
INTO #RecompileQuery
FROM #QueriesRunningSlowerThanNormal
WHERE [DatabaseName] NOT IN ('master', 'msdb', '')

DECLARE @RecompilationSQL NVARCHAR(MAX)
SET @RecompilationSQL = ''

SELECT @RecompilationSQL = @RecompilationSQL
				+ recompileRoutineSQL + CHAR(10)
FROM #RecompileQuery
WHERE recompileRoutineSQL IS NOT NULL

DECLARE @StartOffset INT
DECLARE @Length INT
SET @StartOffset = 0
SET @Length = 4000

WHILE (@StartOffset < LEN(@RecompilationSQL))
BEGIN
	PRINT SUBSTRING(@RecompilationSQL, @StartOffset, @Length)
	SET @StartOffset = @StartOffset + @Length
END

PRINT SUBSTRING(@RecompilationSQL, @StartOffset, @Length)

EXECUTE sp_executesql @RecompilationSQL

DROP TABLE #SlowQueries
DROP TABLE #SlowQueriesByIO
DROP TABLE #QueriesRunningSlowerThanNormal
DROP TABLE #RecompileQuery





-- Listing 10.3 Rebuild/reorganize for a given database

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

CREATE TABLE #FragmentedIndexes(
DatabaseName SYSNAME
, SchemaName SYSNAME
, TableName SYSNAME
, IndexName SYSNAME
, [Fragmentation%] FLOAT)

INSERT INTO #FragmentedIndexes
SELECT
	DB_NAME(DB_ID()) AS DatabaseName
	, ss.name AS SchemaName
	, OBJECT_NAME (s.object_id) AS TableName
	, i.name AS IndexName
	, s.avg_fragmentation_in_percent AS [Fragmentation%]
FROM sys.dm_db_index_physical_stats(db_id(),NULL, NULL, NULL, 'SAMPLED') s
INNER JOIN sys.indexes i ON s.[object_id] = i.[object_id]
	AND s.index_id = i.index_id
INNER JOIN sys.objects o ON s.object_id = o.object_id
INNER JOIN sys.schemas ss ON ss.[schema_id] = o.[schema_id]
WHERE s.database_id = DB_ID()
	AND i.index_id != 0
	AND s.record_count > 0
	AND o.is_ms_shipped = 0

DECLARE @RebuildIndexesSQL NVARCHAR(MAX)
SET @RebuildIndexesSQL = ''

SELECT
@RebuildIndexesSQL = @RebuildIndexesSQL +
CASE
	WHEN [Fragmentation%] > 30
		THEN CHAR(10) + 'ALTER INDEX ' + QUOTENAME(IndexName) + ' ON '
			+ QUOTENAME(SchemaName) + '.'
			+ QUOTENAME(TableName) + ' REBUILD;'
	WHEN [Fragmentation%] > 10
		THEN CHAR(10) + 'ALTER INDEX ' + QUOTENAME(IndexName) + ' ON '
			+ QUOTENAME(SchemaName) + '.'
			+ QUOTENAME(TableName) + ' REORGANIZE;'
	END
FROM #FragmentedIndexes
WHERE [Fragmentation%] > 10

DECLARE @StartOffset INT
DECLARE @Length INT
SET @StartOffset = 0
SET @Length = 4000

WHILE (@StartOffset < LEN(@RebuildIndexesSQL))
BEGIN
	PRINT SUBSTRING(@RebuildIndexesSQL, @StartOffset, @Length)
	SET @StartOffset = @StartOffset + @Length
END

PRINT SUBSTRING(@RebuildIndexesSQL, @StartOffset, @Length)

EXECUTE sp_executesql @RebuildIndexesSQL

DROP TABLE #FragmentedIndexes




-- Listing 10.4 Rebuild/reorganize for all databases on a given server

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

CREATE TABLE #FragmentedIndexes(
	DatabaseName SYSNAME
	, SchemaName SYSNAME
	, TableName SYSNAME
	, IndexName SYSNAME
	, [Fragmentation%] FLOAT)

EXEC sp_MSForEachDB 'USE [?];

INSERT INTO #FragmentedIndexes
SELECT
DB_NAME(DB_ID()) AS DatabaseName
, ss.name AS SchemaName
, OBJECT_NAME (s.object_id) AS TableName
, i.name AS IndexName
, s.avg_fragmentation_in_percent AS [Fragmentation%]
FROM sys.dm_db_index_physical_stats(db_id(),NULL, NULL, NULL,''SAMPLED'') s
INNER JOIN sys.indexes i ON s.[object_id] = i.[object_id]
	AND s.index_id = i.index_id
INNER JOIN sys.objects o ON s.object_id = o.object_id
INNER JOIN sys.schemas ss ON ss.[schema_id] = o.[schema_id]
WHERE s.database_id = DB_ID()
	AND i.index_id != 0
	AND s.record_count > 0
	AND o.is_ms_shipped = 0
;'

DECLARE @RebuildIndexesSQL NVARCHAR(MAX)
SET @RebuildIndexesSQL = ''

SELECT
	@RebuildIndexesSQL = @RebuildIndexesSQL +
	CASE
		WHEN [Fragmentation%] > 30
			THEN CHAR(10) + 'ALTER INDEX ' + QUOTENAME(IndexName) + ' ON '
				+ QUOTENAME(DatabaseName) + '.'+ QUOTENAME(SchemaName) + '.'
				+ QUOTENAME(TableName) + ' REBUILD;'
		WHEN [Fragmentation%] > 10
			THEN CHAR(10) + 'ALTER INDEX ' + QUOTENAME(IndexName) + ' ON '
				+ QUOTENAME(DatabaseName) + '.'+ QUOTENAME(SchemaName) + '.'
				+ QUOTENAME(TableName) + ' REORGANIZE;'
		END
FROM #FragmentedIndexes
WHERE [Fragmentation%] > 10

DECLARE @StartOffset INT
DECLARE @Length INT
SET @StartOffset = 0
SET @Length = 4000

WHILE (@StartOffset < LEN(@RebuildIndexesSQL))
BEGIN
	PRINT SUBSTRING(@RebuildIndexesSQL, @StartOffset, @Length)
	SET @StartOffset = @StartOffset + @Length
END

PRINT SUBSTRING(@RebuildIndexesSQL, @StartOffset, @Length)

EXECUTE sp_executesql @RebuildIndexesSQL

DROP TABLE #FragmentedIndexes



-- Listing 10.5 Intelligently update statistics梥imple version

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
SELECT
	ss.name AS SchemaName
	, st.name AS TableName
	, si.name AS IndexName
	, si.type_desc AS IndexType
	, STATS_DATE(si.object_id,si.index_id) AS StatsLastTaken
	, ssi.rowcnt
	, ssi.rowmodctr
INTO #IndexUsage
FROM sys.indexes si
INNER JOIN sys.sysindexes ssi ON si.object_id = ssi.id
					AND si.name = ssi.name
INNER JOIN sys.tables st ON st.[object_id] = si.[object_id]
INNER JOIN sys.schemas ss ON ss.[schema_id] = st.[schema_id]
WHERE st.is_ms_shipped = 0
	AND si.index_id != 0
	AND ssi.rowcnt > 100
	AND ssi.rowmodctr > 0

DECLARE @UpdateStatisticsSQL NVARCHAR(MAX)
SET @UpdateStatisticsSQL = ''

SELECT
	@UpdateStatisticsSQL = @UpdateStatisticsSQL
	+ CHAR(10) + 'UPDATE STATISTICS '
	+ QUOTENAME(SchemaName) + '.' + QUOTENAME(TableName)
	+ ' ' + QUOTENAME(IndexName) + ' WITH SAMPLE '
	+ CASE
		WHEN rowcnt < 500000 THEN '100 PERCENT'
		WHEN rowcnt < 1000000 THEN '50 PERCENT'
		WHEN rowcnt < 5000000 THEN '25 PERCENT'
		WHEN rowcnt < 10000000 THEN '10 PERCENT'
		WHEN rowcnt < 50000000 THEN '2 PERCENT'
		WHEN rowcnt < 100000000 THEN '1 PERCENT'
		ELSE '3000000 ROWS '
	END
	+ '-- ' + CAST(rowcnt AS VARCHAR(22)) + ' rows'
FROM #IndexUsage

DECLARE @StartOffset INT
DECLARE @Length INT
SET @StartOffset = 0
SET @Length = 4000

WHILE (@StartOffset < LEN(@UpdateStatisticsSQL))
BEGIN
	PRINT SUBSTRING(@UpdateStatisticsSQL, @StartOffset, @Length)
	SET @StartOffset = @StartOffset + @Length
END

PRINT SUBSTRING(@UpdateStatisticsSQL, @StartOffset, @Length)

EXECUTE sp_executesql @UpdateStatisticsSQL

DROP TABLE #IndexUsage





-- Listing 10.6 Intelligently update statistics梩ime-based version

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

IF EXISTS
	(SELECT 1
		FROM sys.indexes si
		INNER JOIN sys.sysindexes ssi ON si.object_id = ssi.id
			AND si.name = ssi.name
		INNER JOIN sys.tables st ON st.[object_id] = si.[object_id]
		INNER JOIN sys.schemas ss ON ss.[schema_id] = st.[schema_id]
		WHERE st.is_ms_shipped = 0
			AND si.index_id != 0
			AND ssi.rowcnt > 100
			AND ssi.rowmodctr > 0)
BEGIN

DECLARE @StatsMarker NVARCHAR(2000)
DECLARE @SamplingComplete BIT
DECLARE @RowsToBenchMark BIGINT
SET @RowsToBenchMark = 500
SET @SamplingComplete = 0

DECLARE @TotalStatsTime BIGINT
DECLARE @StartTime DATETIME
DECLARE @TimePerRow FLOAT
WHILE (@SamplingComplete = 0)
BEGIN

	SELECT TOP 1 @StatsMarker = 'UPDATE STATISTICS '
		+ QUOTENAME(ss.name) + '.' + QUOTENAME(st.name)
		+ ' ' + QUOTENAME(si.name) + ' WITH SAMPLE '
		+ CAST(@RowsToBenchMark AS VARCHAR(22)) + ' ROWS'
	FROM sys.indexes si
	INNER JOIN sys.sysindexes ssi ON si.object_id = ssi.id
			AND si.name = ssi.name
	INNER JOIN sys.tables st ON st.[object_id] = si.[object_id]
	INNER JOIN sys.schemas ss ON ss.[schema_id] = st.[schema_id]
	WHERE st.is_ms_shipped = 0 -- User tables only
		AND si.index_id != 0 -- ignore heaps
		AND ssi.rowcnt > @RowsToBenchMark
	ORDER BY ssi.rowcnt
	
	IF @@ROWCOUNT > 0
	BEGIN
		PRINT 'Testing sampling time with: ' + @StatsMarker
		
		SET @StartTime = GETDATE()
		
		EXECUTE sp_executesql @StatsMarker
		
		SET @TotalStatsTime = DATEDIFF(SECOND, @StartTime, GETDATE())
		PRINT '@TotalStatsTime: ' + CAST(@TotalStatsTime AS VARCHAR(22))
		
		IF (@TotalStatsTime > 5)
		BEGIN
			SET @TimePerRow = @TotalStatsTime /	(@RowsToBenchMark * 1.0)
			PRINT @TimePerRow
			SET @SamplingComplete = 1
		END
		ELSE
			SET @RowsToBenchMark = @RowsToBenchMark * 10
	END
	ELSE
	BEGIN
		DECLARE @ErrorMsg VARCHAR(200)
		SET @ErrorMsg = 'No indexes found with @RowsToBenchMark > '
						+ CAST(@RowsToBenchMark AS VARCHAR(22))
		RAISERROR(@ErrorMsg, 16, 1)
		RETURN
	END
END

DECLARE @RowsToSample BIGINT
SET @RowsToSample = 0

SELECT
	ss.name AS SchemaName
	, st.name AS TableName
	, si.name AS IndexName
	, si.type_desc AS IndexType
	, STATS_DATE(si.object_id,si.index_id) AS StatsLastTaken
	, ssi.rowcnt
	, ssi.rowmodctr
	, @RowsToSample AS RowsToSample
INTO #IndexUsage
FROM sys.indexes si
INNER JOIN sys.sysindexes ssi ON si.object_id = ssi.id
	AND si.name = ssi.name
INNER JOIN sys.tables st ON st.[object_id] = si.[object_id]
INNER JOIN sys.schemas ss ON ss.[schema_id] = st.[schema_id]
WHERE st.is_ms_shipped = 0
	AND si.index_id != 0
	AND ssi.rowcnt > 100
	AND ssi.rowmodctr > 0
	
DECLARE @MaxSamplingTimeInSeconds INT
SET @MaxSamplingTimeInSeconds = 600 -- 10 mins

DECLARE @WorkIsWithinTimeLimit BIT
SET @WorkIsWithinTimeLimit = 0

DECLARE @TotalTimeForAllStats INT
DECLARE @ReduceFraction FLOAT
SET @ReduceFraction = 1.0

DECLARE @ReduceFractionSmall FLOAT
SET @ReduceFractionSmall = 1.0

UPDATE #IndexUsage
SET RowsToSample =
	CASE
		WHEN rowcnt < 100000000 THEN rowcnt
		ELSE 3000000
	END

WHILE (@WorkIsWithinTimeLimit = 0)
BEGIN
	UPDATE #IndexUsage
	SET RowsToSample =
		CASE
			WHEN rowcnt < 500000 THEN rowcnt * @ReduceFractionSmall
			WHEN rowcnt < 1000000 THEN rowcnt / 2 * @ReduceFractionSmall
			WHEN rowcnt < 5000000 THEN rowcnt / 4 * @ReduceFractionSmall
			WHEN rowcnt < 10000000 THEN rowcnt / 10 * @ReduceFraction
			WHEN rowcnt < 50000000 THEN rowcnt / 50 * @ReduceFraction
			WHEN rowcnt < 100000000 THEN rowcnt / 100 * @ReduceFraction
			ELSE 3000000 * @ReduceFraction
		END
		
	SELECT @TotalTimeForAllStats = SUM(RowsToSample) * @TimePerRow
	FROM #IndexUsage
	
	PRINT '@TotalTimeForAllStats: '
			+ CAST(@TotalTimeForAllStats AS VARCHAR(22))
	
	IF (@TotalTimeForAllStats < @MaxSamplingTimeInSeconds)
		SET @WorkIsWithinTimeLimit = 1
	ELSE
	BEGIN
		SET @ReduceFraction = @ReduceFraction - 0.01
		SET @ReduceFractionSmall = @ReduceFractionSmall - 0.001
	END
END

DECLARE @UpdateStatisticsSQL NVARCHAR(MAX)
SET @UpdateStatisticsSQL = ''

SELECT
	@UpdateStatisticsSQL = @UpdateStatisticsSQL
	+ CHAR(10) + 'UPDATE STATISTICS ' + QUOTENAME(SchemaName)
	+ '.' + QUOTENAME(TableName)
	+ ' ' + QUOTENAME(IndexName) + ' WITH SAMPLE '
	+ CAST(RowsToSample AS VARCHAR(22)) + ' ROWS '
FROM #IndexUsage

DECLARE @StartOffset INT
DECLARE @Length INT
SET @StartOffset = 0
SET @Length = 4000

WHILE (@StartOffset < LEN(@UpdateStatisticsSQL))
BEGIN
	PRINT SUBSTRING(@UpdateStatisticsSQL, @StartOffset, @Length)
	SET @StartOffset = @StartOffset + @Length
END

PRINT SUBSTRING(@UpdateStatisticsSQL, @StartOffset, @Length)

EXECUTE sp_executesql @UpdateStatisticsSQL

DROP TABLE #IndexUsage

END






-- Listing 10.7 Update statistics used by a SQL routine or a time interval

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

SELECT
	SchemaName = ss.name
	, TableName = st.name
	, IndexName = si.name
	, si.type_desc AS IndexType
	, user_updates = ISNULL(ius.user_updates, 0)
	, user_seeks = ISNULL(ius.user_seeks, 0)
	, user_scans = ISNULL(ius.user_scans, 0)
	, user_lookups = ISNULL(ius.user_lookups, 0)
	, ssi.rowcnt
	, ssi.rowmodctr
INTO #IndexStatsPre
FROM sys.dm_db_index_usage_stats ius
RIGHT OUTER JOIN sys.indexes si ON ius.[object_id] = si.[object_id]
	AND ius.index_id = si.index_id
INNER JOIN sys.sysindexes ssi ON si.object_id = ssi.id
	AND si.name = ssi.name
INNER JOIN sys.tables st ON st.[object_id] = si.[object_id]
INNER JOIN sys.schemas ss ON ss.[schema_id] = st.[schema_id]
WHERE ius.database_id = DB_ID()
	AND st.is_ms_shipped = 0
	
WAITFOR DELAY '00:10:00'

SELECT
	SchemaName = ss.name
	, TableName = st.name
	, IndexName = si.name
	, si.type_desc AS IndexType
	, user_updates = ISNULL(ius.user_updates, 0)
	, user_seeks = ISNULL(ius.user_seeks, 0)
	, user_scans = ISNULL(ius.user_scans, 0)
	, user_lookups = ISNULL(ius.user_lookups, 0)
	, ssi.rowcnt
	, ssi.rowmodctr
INTO #IndexStatsPost
FROM sys.dm_db_index_usage_stats ius
RIGHT OUTER JOIN sys.indexes si ON ius.[object_id] = si.[object_id]
	AND ius.index_id = si.index_id
INNER JOIN sys.sysindexes ssi ON si.object_id = ssi.id
	AND si.name = ssi.name
INNER JOIN sys.tables st ON st.[object_id] = si.[object_id]
INNER JOIN sys.schemas ss ON ss.[schema_id] = st.[schema_id]
WHERE ius.database_id = DB_ID()
	AND st.is_ms_shipped = 0
	
SELECT
	po.[SchemaName]
	, po.[TableName]
	, po.[IndexName]
	, po.rowcnt
	, po.[IndexType]
	, [User Updates] = po.user_updates - ISNULL(pr.user_updates, 0)
	, [User Seeks] = po.user_seeks - ISNULL(pr.user_seeks, 0)
	, [User Scans] = po.user_scans - ISNULL(pr.user_scans, 0)
	, [User Lookups] = po.user_lookups - ISNULL(pr.user_lookups, 0)
	, [Rows Inserted] = po.rowcnt - ISNULL(pr.rowcnt, 0)
	, [Updates I/U/D] = po.rowmodctr - ISNULL(pr.rowmodctr, 0)
INTO #IndexUsage
FROM #IndexStatsPost po
LEFT OUTER JOIN #IndexStatsPre pr ON pr.SchemaName = po.SchemaName
	AND pr.TableName = po.TableName
	AND pr.IndexName = po.IndexName
	AND pr.IndexType = po.IndexType
WHERE ISNULL(pr.user_updates, 0) != po.user_updates
	OR ISNULL(pr.user_seeks, 0) != po.user_seeks
	OR ISNULL(pr.user_scans, 0) != po.user_scans
	OR ISNULL(pr.user_lookups, 0) != po.user_lookups
	
DECLARE @UpdateStatisticsSQL NVARCHAR(MAX)
SET @UpdateStatisticsSQL = ''

SELECT
	@UpdateStatisticsSQL = @UpdateStatisticsSQL
	+ CHAR(10) + 'UPDATE STATISTICS ' + QUOTENAME(SchemaName)
	+ '.' + QUOTENAME(TableName)
	+ ' ' + QUOTENAME(IndexName) + ' WITH SAMPLE '
	+ CASE
		WHEN rowcnt < 500000 THEN '100 PERCENT'
		WHEN rowcnt < 1000000 THEN '50 PERCENT'
		WHEN rowcnt < 5000000 THEN '25 PERCENT'
		WHEN rowcnt < 10000000 THEN '10 PERCENT'
		WHEN rowcnt < 50000000 THEN '2 PERCENT'
		WHEN rowcnt < 100000000 THEN '1 PERCENT'
		ELSE '3000000 ROWS '
	END
FROM #IndexUsage
WHERE [User Seeks] != 0 OR [User Scans] != 0 OR [User Lookups] != 0

DECLARE @StartOffset INT
DECLARE @Length INT
SET @StartOffset = 0
SET @Length = 4000

WHILE (@StartOffset < LEN(@UpdateStatisticsSQL))
BEGIN
	PRINT SUBSTRING(@UpdateStatisticsSQL, @StartOffset, @Length)
	SET @StartOffset = @StartOffset + @Length
END

PRINT SUBSTRING(@UpdateStatisticsSQL, @StartOffset, @Length)

EXECUTE sp_executesql @UpdateStatisticsSQL

DROP TABLE #IndexStatsPre
DROP TABLE #IndexStatsPost
DROP TABLE #IndexUsage




-- Listing 10.8 Automatically create any missing indexes

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

SELECT TOP 20
	'CREATE NONCLUSTERED INDEX '
	+ QUOTENAME('IX_AutoGenerated_'
	+ REPLACE(REPLACE(CONVERT(VARCHAR(25), GETDATE(), 113), ' ', '_'), ':', '_')
	+ '_' + CAST(d.index_handle AS VARCHAR(22))
	)
	+ ' ON ' + d.[statement] + '('
	+ CASE
		WHEN d.equality_columns IS NULL THEN d.inequality_columns
		WHEN d.inequality_columns IS NULL THEN d.equality_columns
		ELSE d.equality_columns + ',' + d.inequality_columns
	END
	+ ')'
	+ CASE
		WHEN d.included_columns IS NOT NULL THEN
		' INCLUDE ( ' + d.included_columns + ')'
		ELSE ''
	END AS MissingIndexSQL
	, ROUND(s.avg_total_user_cost * s.avg_user_impact
		* (s.user_seeks + s.user_scans),0) AS [Total Cost]
	, d.[statement] AS [Table Name]
	, d.equality_columns
	, d.inequality_columns
	, d.included_columns
INTO #MissingIndexes
FROM sys.dm_db_missing_index_groups g
INNER JOIN sys.dm_db_missing_index_group_stats s
	ON s.group_handle = g.index_group_handle
INNER JOIN sys.dm_db_missing_index_details d
	ON d.index_handle = g.index_handle
ORDER BY [Total Cost] DESC

DECLARE @MissingIndexesSQL NVARCHAR(MAX)
SET @MissingIndexesSQL = ''

SELECT
@MissingIndexesSQL = @MissingIndexesSQL + MissingIndexSQL + CHAR(10)
FROM #MissingIndexes

DECLARE @StartOffset INT
DECLARE @Length INT
SET @StartOffset = 0
SET @Length = 4000

WHILE (@StartOffset < LEN(@MissingIndexesSQL))
BEGIN
	PRINT SUBSTRING(@MissingIndexesSQL, @StartOffset, @Length)
	SET @StartOffset = @StartOffset + @Length
END

PRINT SUBSTRING(@MissingIndexesSQL, @StartOffset, @Length)

EXECUTE sp_executesql @MissingIndexesSQL

DROP TABLE #MissingIndexes






-- Listing 10.9 Automatically disable or drop unused indexes

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
SELECT
DB_NAME() AS DatabaseName
, SCHEMA_NAME(o.Schema_ID) AS SchemaName
, OBJECT_NAME(s.[object_id]) AS TableName
, i.name AS IndexName
, s.user_updates
, s.system_seeks + s.system_scans + s.system_lookups
AS [System usage]
INTO #TempUnusedIndexes
FROM sys.dm_db_index_usage_stats s
INNER JOIN sys.indexes i ON s.[object_id] = i.[object_id]
	AND s.index_id = i.index_id
INNER JOIN sys.objects o ON i.object_id = O.object_id
WHERE 1=2

EXEC sp_MSForEachDB 'USE [?];
INSERT INTO #TempUnusedIndexes
SELECT TOP 20
DB_NAME() AS DatabaseName
	, SCHEMA_NAME(o.Schema_ID) AS SchemaName
	, OBJECT_NAME(s.[object_id]) AS TableName
	, i.name AS IndexName
	, s.user_updates
	, s.system_seeks + s.system_scans + s.system_lookups AS [System usage]
FROM sys.dm_db_index_usage_stats s
INNER JOIN sys.indexes i ON s.[object_id] = i.[object_id]
	AND s.index_id = i.index_id
INNER JOIN sys.objects o ON i.object_id = O.object_id
WHERE s.database_id = DB_ID()
	AND OBJECTPROPERTY(s.[object_id], ''IsMsShipped'') = 0
	AND user_seeks = 0
	AND user_scans = 0
	AND user_lookups = 0
	AND i.name IS NOT NULL
ORDER BY user_updates DESC'

DECLARE @DisableOrDrop INT
SET @DisableOrDrop = 1

DECLARE @DisableIndexesSQL NVARCHAR(MAX)
SET @DisableIndexesSQL = ''

SELECT
	@DisableIndexesSQL = @DisableIndexesSQL +
	CASE
	WHEN @DisableOrDrop = 1
		THEN CHAR(10) + 'ALTER INDEX ' + QUOTENAME(IndexName) + ' ON '
			+ QUOTENAME(DatabaseName) + '.'+ QUOTENAME(SchemaName) + '.'
			+ QUOTENAME(TableName) + ' DISABLE;'
	ELSE CHAR(10) + 'DROP INDEX ' + QUOTENAME(IndexName) + ' ON '
		+ QUOTENAME(DatabaseName) + '.'+ QUOTENAME(SchemaName) + '.'
		+ QUOTENAME(TableName)
	END
FROM #TempUnusedIndexes

DECLARE @StartOffset INT
DECLARE @Length INT
SET @StartOffset = 0
SET @Length = 4000

WHILE (@StartOffset < LEN(@DisableIndexesSQL))
BEGIN
	PRINT SUBSTRING(@DisableIndexesSQL, @StartOffset, @Length)
	SET @StartOffset = @StartOffset + @Length
END

PRINT SUBSTRING(@DisableIndexesSQL, @StartOffset, @Length)

EXECUTE sp_executesql @DisableIndexesSQL

DROP TABLE #TempUnusedIndexes




-- Listing 11.1 Finding everyone抯 last-run query

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

SELECT c.session_id, s.host_name, s.login_name, s.status
	, st.text, s.login_time, s.program_name, *
FROM sys.dm_exec_connections c
INNER JOIN sys.dm_exec_sessions s ON c.session_id = s.session_id
CROSS APPLY sys.dm_exec_sql_text(most_recent_sql_handle) AS st
ORDER BY c.session_id




-- Listing 11.2 Generic performance test harness

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

SELECT
	sql_handle, plan_handle, total_elapsed_time, total_worker_time
	, total_logical_reads, total_logical_writes, total_clr_time
	, execution_count, statement_start_offset, statement_end_offset
INTO #PreWorkQuerySnapShot
FROM sys.dm_exec_query_stats

EXEC PutYourQueryHere

SELECT
	sql_handle, plan_handle, total_elapsed_time, total_worker_time
	, total_logical_reads, total_logical_writes, total_clr_time
	, execution_count, statement_start_offset, statement_end_offset
INTO #PostWorkQuerySnapShot
FROM sys.dm_exec_query_stats

SELECT
	p2.total_elapsed_time - ISNULL(p1.total_elapsed_time, 0) AS [Duration]
	, p2.total_worker_time - ISNULL(p1.total_worker_time, 0) AS [Time on CPU]
	, (p2.total_elapsed_time - ISNULL(p1.total_elapsed_time, 0)) -
		(p2.total_worker_time - ISNULL(p1.total_worker_time, 0)) AS [Time blocked]
	, p2.total_logical_reads - ISNULL(p1.total_logical_reads, 0) AS [Reads]
	, p2.total_logical_writes - ISNULL(p1.total_logical_writes, 0) AS [Writes]
	, p2.total_clr_time - ISNULL(p1.total_clr_time, 0) AS [CLR time]
	, p2.execution_count - ISNULL(p1.execution_count, 0) AS [Executions]
	, SUBSTRING (qt.text,p2.statement_start_offset/2 + 1,
	((CASE WHEN p2.statement_end_offset = -1
		THEN LEN(CONVERT(NVARCHAR(MAX), qt.text)) * 2
		ELSE p2.statement_end_offset
	END - p2.statement_start_offset)/2) + 1) AS [Individual Query]
	, qt.text AS [Parent Query]
	, DB_NAME(qt.dbid) AS DatabaseName
FROM #PreWorkQuerySnapShot p1
RIGHT OUTER JOIN
#PostWorkQuerySnapShot p2 ON p2.sql_handle =ISNULL(p1.sql_handle, p2.sql_handle)
	AND p2.plan_handle = ISNULL(p1.plan_handle, p2.plan_handle)
	AND p2.statement_start_offset =ISNULL(p1.statement_start_offset, p2.statement_start_offset)
	AND p2.statement_end_offset =ISNULL(p1.statement_end_offset, p2.statement_end_offset)
CROSS APPLY sys.dm_exec_sql_text(p2.sql_handle) as qt
WHERE p2.execution_count != ISNULL(p1.execution_count, 0)
ORDER BY qt.text, p2.statement_start_offset

DROP TABLE #PreWorkQuerySnapShot
DROP TABLE #PostWorkQuerySnapShot





-- Listing 11.3 Determining the performance impact of a system upgrade

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

SELECT
	total_elapsed_time, total_worker_time, total_logical_reads
	, total_logical_writes, total_clr_time, execution_count
	, statement_start_offset, statement_end_offset, sql_handle, plan_handle
INTO #prework
FROM sys.dm_exec_query_stats

EXEC PutYourWorkloadHere

SELECT
	total_elapsed_time, total_worker_time, total_logical_reads
	, total_logical_writes, total_clr_time, execution_count
	, statement_start_offset, statement_end_offset, sql_handle, plan_handle
INTO #postwork
FROM sys.dm_exec_query_stats

SELECT
	SUM(p2.total_elapsed_time - ISNULL(p1.total_elapsed_time, 0)) AS [TotalDuration]
	, SUM(p2.total_worker_time - ISNULL(p1.total_worker_time, 0)) AS [Total Time on CPU]
	, SUM((p2.total_elapsed_time - ISNULL(p1.total_elapsed_time, 0)) -
				(p2.total_worker_time - ISNULL(p1.total_worker_time, 0))) AS [Total Time Waiting]
	, SUM(p2.total_logical_reads - ISNULL(p1.total_logical_reads, 0)) AS [TotalReads]
	, SUM(p2.total_logical_writes - ISNULL(p1.total_logical_writes, 0)) AS [TotalWrites]
	, SUM(p2.total_clr_time - ISNULL(p1.total_clr_time, 0)) AS [Total CLR time]
	, SUM(p2.execution_count - ISNULL(p1.execution_count, 0)) AS [Total Executions]
	, DB_NAME(qt.dbid) AS DatabaseName
FROM #prework p1
RIGHT OUTER JOIN
#postwork p2 ON p2.sql_handle = ISNULL(p1.sql_handle, p2.sql_handle)
	AND p2.plan_handle = ISNULL(p1.plan_handle, p2.plan_handle)
	AND p2.statement_start_offset =ISNULL(p1.statement_start_offset, p2.statement_start_offset)
	AND p2.statement_end_offset =ISNULL(p1.statement_end_offset, p2.statement_end_offset)
CROSS APPLY sys.dm_exec_sql_text(p2.sql_handle) as qt
WHERE p2.execution_count != ISNULL(p1.execution_count, 0)
GROUP BY DB_NAME(qt.dbid)

SELECT
	SUM(p2.total_elapsed_time - ISNULL(p1.total_elapsed_time, 0)) AS [TotalDuration]
	, SUM(p2.total_worker_time - ISNULL(p1.total_worker_time, 0)) AS [Total Time on CPU]
	, SUM((p2.total_elapsed_time - ISNULL(p1.total_elapsed_time, 0))
			- (p2.total_worker_time - ISNULL(p1.total_worker_time, 0))) AS [Total Time Waiting]
	, SUM(p2.total_logical_reads - ISNULL(p1.total_logical_reads, 0)) AS [TotalReads]
	, SUM(p2.total_logical_writes - ISNULL(p1.total_logical_writes, 0)) AS [TotalWrites]
	, SUM(p2.total_clr_time - ISNULL(p1.total_clr_time, 0)) AS [Total CLR time]
	, SUM(p2.execution_count - ISNULL(p1.execution_count, 0)) AS [Total Executions]
	, DB_NAME(qt.dbid) AS DatabaseName
	, qt.text AS [Parent Query]
FROM #prework p1
RIGHT OUTER JOIN
#postwork p2 ON p2.sql_handle = ISNULL(p1.sql_handle, p2.sql_handle)
	AND p2.plan_handle = ISNULL(p1.plan_handle, p2.plan_handle)
	AND p2.statement_start_offset =ISNULL(p1.statement_start_offset, p2.statement_start_offset)
	AND p2.statement_end_offset =ISNULL(p1.statement_end_offset, p2.statement_end_offset)
CROSS APPLY sys.dm_exec_sql_text(p2.sql_handle) as qt
WHERE p2.execution_count != ISNULL(p1.execution_count, 0)
GROUP BY DB_NAME(qt.dbid), qt.text
ORDER BY [TotalDuration] DESC

SELECT
	p2.total_elapsed_time - ISNULL(p1.total_elapsed_time, 0) AS [TotalDuration]
	, p2.total_worker_time - ISNULL(p1.total_worker_time, 0) AS [Total Time on CPU]
	, (p2.total_elapsed_time - ISNULL(p1.total_elapsed_time, 0))
		- (p2.total_worker_time - ISNULL(p1.total_worker_time, 0)) AS [Total Time Waiting]
	, p2.total_logical_reads - ISNULL(p1.total_logical_reads, 0) AS [TotalReads]
	, p2.total_logical_writes - ISNULL(p1.total_logical_writes, 0) AS [TotalWrites]
	, p2.total_clr_time - ISNULL(p1.total_clr_time, 0) AS [Total CLR time]
	, p2.execution_count - ISNULL(p1.execution_count, 0) AS [Total Executions]
	, SUBSTRING (qt.text,p2.statement_start_offset/2 + 1,
	((CASE WHEN p2.statement_end_offset = -1
		THEN LEN(CONVERT(NVARCHAR(MAX), qt.text)) * 2
		ELSE p2.statement_end_offset
	END - p2.statement_start_offset)/2) + 1) AS [Individual Query]
	, qt.text AS [Parent Query]
	, DB_NAME(qt.dbid) AS DatabaseName
FROM #prework p1
RIGHT OUTER JOIN
#postwork p2 ON p2.sql_handle = ISNULL(p1.sql_handle, p2.sql_handle)
	AND p2.plan_handle = ISNULL(p1.plan_handle, p2.plan_handle)
	AND p2.statement_start_offset = ISNULL(p1.statement_start_offset, p2.statement_start_offset)
	AND p2.statement_end_offset = ISNULL(p1.statement_end_offset, p2.statement_end_offset)
CROSS APPLY sys.dm_exec_sql_text(p2.sql_handle) as qt
WHERE p2.execution_count != ISNULL(p1.execution_count, 0)
ORDER BY [TotalDuration] DESC

DROP TABLE #prework
DROP TABLE #postwork




-- Listing 11.4 Estimating when a job will finish

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

SELECT r.percent_complete
	, DATEDIFF(MINUTE, start_time, GETDATE()) AS Age
	, DATEADD(MINUTE, DATEDIFF(MINUTE, start_time, GETDATE()) /
		percent_complete * 100, start_time) AS EstimatedEndTime
	, t.Text AS ParentQuery
	, SUBSTRING (t.text,(r.statement_start_offset/2) + 1,
	((CASE WHEN r.statement_end_offset = -1
		THEN LEN(CONVERT(NVARCHAR(MAX), t.text)) * 2
		ELSE r.statement_end_offset
	END - r.statement_start_offset)/2) + 1) AS IndividualQuery
	, start_time
	, DB_NAME(Database_Id) AS DatabaseName
	, Status
FROM sys.dm_exec_requests r
CROSS APPLY sys.dm_exec_sql_text(sql_handle) t
WHERE session_id > 50
	AND percent_complete > 0
ORDER BY percent_complete DESC




-- Listing 11.5 Who抯 doing what and when?

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
CREATE TABLE dbo.WhatsGoingOnHistory(
	[Runtime] [DateTime],
	[session_id] [smallint] NOT NULL,
	[login_name] [varchar](128) NOT NULL,
	[host_name] [varchar](128) NULL,
	[DBName] [varchar](128) NULL,
	[Individual Query] [varchar](max) NULL,
	[Parent Query] [varchar](200) NULL,
	[status] [varchar](30) NULL,
	[start_time] [datetime] NULL,
	[wait_type] [varchar](60) NULL,
	[program_name] [varchar](128) NULL
)
GO

CREATE UNIQUE NONCLUSTERED INDEX
[NONCLST_WhatsGoingOnHistory] ON [dbo].[WhatsGoingOnHistory]
([Runtime] ASC, [session_id] ASC)
GO

INSERT INTO dbo.WhatsGoingOnHistory
SELECT
	GETDATE()
	, s.session_id
	, s.login_name
	, s.host_name
	, DB_NAME(r.database_id) AS DBName
	, SUBSTRING (t.text,(r.statement_start_offset/2) + 1,
	((CASE WHEN r.statement_end_offset = -1
		THEN LEN(CONVERT(NVARCHAR(MAX), t.text)) * 2
		ELSE r.statement_end_offset
	END - r.statement_start_offset)/2) + 1) AS [Individual Query]
	, SUBSTRING(text, 1, 200) AS [Parent Query]
	, r.status
	, r.start_time
	, r.wait_type
	, s.program_name
FROM sys.dm_exec_sessions s
INNER JOIN sys.dm_exec_connections c ON s.session_id = c.session_id
INNER JOIN sys.dm_exec_requests r ON c.connection_id = r.connection_id
CROSS APPLY sys.dm_exec_sql_text(r.sql_handle) t
WHERE s.session_id > 50
	AND r.session_id != @@spid
	
WAITFOR DELAY '00:01:00'
GO 1440 -- 60 * 24 (one day)






-- Listing 11.6 Determining where your query spends its time

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

SELECT
	sql_handle, plan_handle, total_elapsed_time, total_worker_time
	, total_logical_reads, total_logical_writes, total_clr_time
	, execution_count, statement_start_offset, statement_end_offset
INTO #PreWorkQuerySnapShot
FROM sys.dm_exec_query_stats

EXEC MO.PNLYearToDate_v01iws
			@pControlOrgIds = '537'
			, @pCOBStart = '27 may 2009'
			, @pCOBEnd = '27 may 2009'

SELECT
	sql_handle, plan_handle, total_elapsed_time, total_worker_time
	, total_logical_reads, total_logical_writes, total_clr_time
	, execution_count, statement_start_offset, statement_end_offset,
	last_execution_time
INTO #PostWorkQuerySnapShot
FROM sys.dm_exec_query_stats

SELECT
	p2.total_elapsed_time - ISNULL(p1.total_elapsed_time, 0) AS [Duration]
	, p2.total_worker_time - ISNULL(p1.total_worker_time, 0) AS [Time on CPU]
	, (p2.total_elapsed_time - ISNULL(p1.total_elapsed_time, 0)) -
		(p2.total_worker_time - ISNULL(p1.total_worker_time, 0)) AS [Time waiting]
	, p2.total_logical_reads - ISNULL(p1.total_logical_reads, 0) AS [Reads]
	, p2.total_logical_writes - ISNULL(p1.total_logical_writes, 0) AS [Writes]
	, p2.total_clr_time - ISNULL(p1.total_clr_time, 0) AS [CLR time]
	, p2.execution_count - ISNULL(p1.execution_count, 0) AS [Executions]
	, p2.last_execution_time
	, SUBSTRING (qt.text,p2.statement_start_offset/2 + 1,
	((CASE WHEN p2.statement_end_offset = -1
		THEN LEN(CONVERT(NVARCHAR(MAX), qt.text)) * 2
		ELSE p2.statement_end_offset
	END - p2.statement_start_offset)/2) + 1) AS [Individual Query]
	, qt.text AS [Parent Query]
	, DB_NAME(qt.dbid) AS DatabaseName
FROM #PreWorkQuerySnapShot p1
RIGHT OUTER JOIN
#PostWorkQuerySnapShot p2
		ON p2.sql_handle = ISNULL(p1.sql_handle, p2.sql_handle)
	AND p2.plan_handle = ISNULL(p1.plan_handle, p2.plan_handle)
	AND p2.statement_start_offset = ISNULL(p1.statement_start_offset, p2.statement_start_offset)
	AND p2.statement_end_offset = ISNULL(p1.statement_end_offset, p2.statement_end_offset)
CROSS APPLY sys.dm_exec_sql_text(p2.sql_handle) as qt
WHERE p2.execution_count != ISNULL(p1.execution_count, 0)
	AND qt.text LIKE '%PNLYearToDate_v01iws %'
ORDER BY [Parent Query], p2.statement_start_offset

DROP TABLE #PreWorkQuerySnapShot
DROP TABLE #PostWorkQuerySnapShot





-- Listing 11.7 Memory used per database

SET TRAN ISOLATION LEVEL READ UNCOMMITTED

SELECT
	ISNULL(DB_NAME(database_id), 'ResourceDb') AS DatabaseName
	, CAST(COUNT(row_count) * 8.0 / (1024.0) AS DECIMAL(28,2)) AS [Size (MB)]
FROM sys.dm_os_buffer_descriptors
GROUP BY database_id
ORDER BY DatabaseName





-- Listing 11.8 Memory used by objects in the current database

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

SELECT
	OBJECT_NAME(p.[object_id]) AS [TableName]
	, (COUNT(*) * 8) / 1024 AS [Buffer size(MB)]
	, ISNULL(i.name, '-- HEAP --') AS ObjectName
	, COUNT(*) AS NumberOf8KPages
FROM sys.allocation_units AS a
INNER JOIN sys.dm_os_buffer_descriptors AS b
	ON a.allocation_unit_id = b.allocation_unit_id
INNER JOIN sys.partitions AS p
INNER JOIN sys.indexes i ON p.index_id = i.index_id
			AND p.[object_id] = i.[object_id]
	ON a.container_id = p.hobt_id
WHERE b.database_id = DB_ID()
	AND p.[object_id] > 100
GROUP BY p.[object_id], i.name






-- Listing 11.9 I/O stalls at the database level

SET TRAN ISOLATION LEVEL READ UNCOMMITTED

SELECT DB_NAME(database_id) AS [DatabaseName]
	, SUM(CAST(io_stall / 1000.0 AS DECIMAL(20,2))) AS [IO stall (secs)]
	, SUM(CAST(num_of_bytes_read / 1024.0 / 1024.0 AS DECIMAL(20,2))) AS [IO read (MB)]
	, SUM(CAST(num_of_bytes_written / 1024.0 / 1024.0 AS DECIMAL(20,2))) AS [IO written (MB)]
	, SUM(CAST((num_of_bytes_read + num_of_bytes_written)
		/ 1024.0 / 1024.0 AS DECIMAL(20,2))) AS [TotalIO (MB)]
FROM sys.dm_io_virtual_file_stats(NULL, NULL)
GROUP BY database_id
ORDER BY [IO stall (secs)] DESC




-- Listing 11.10 I/O stalls at the file level

SET TRAN ISOLATION LEVEL READ UNCOMMITTED

SELECT DB_NAME(database_id) AS [DatabaseName]
	, file_id
	, SUM(CAST(io_stall / 1000.0 AS DECIMAL(20,2))) AS [IO stall (secs)]
	, SUM(CAST(num_of_bytes_read / 1024.0 / 1024.0 AS DECIMAL(20,2))) AS [IO read (MB)]
	, SUM(CAST(num_of_bytes_written / 1024.0 / 1024.0 AS DECIMAL(20,2))) AS [IO written (MB)]
	, SUM(CAST((num_of_bytes_read + num_of_bytes_written)
		/ 1024.0 / 1024.0 AS DECIMAL(20,2))) AS [TotalIO (MB)]
FROM sys.dm_io_virtual_file_stats(NULL, NULL)
GROUP BY database_id, file_id
ORDER BY [IO stall (secs)] DESC





-- Listing 11.11 Average read/write times per file, per database

SET TRAN ISOLATION LEVEL READ UNCOMMITTED

SELECT DB_NAME(database_id) AS DatabaseName
	, file_id
	, io_stall_read_ms / num_of_reads AS 'Average read time'
	, io_stall_write_ms / num_of_writes AS 'Average write time'
FROM sys.dm_io_virtual_file_stats(NULL, NULL)
WHERE num_of_reads > 0 and num_of_writes > 0
ORDER BY DatabaseName




-- Listing 11.12 Simple trace utility

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

SELECT
	sql_handle, plan_handle, total_elapsed_time, total_worker_time
	, total_logical_reads, total_logical_writes, total_clr_time
	, execution_count, statement_start_offset, statement_end_offset
INTO #PreWorkQuerySnapShot
FROM sys.dm_exec_query_stats

WAITFOR DELAY '00:01:00'

SELECT
	sql_handle, plan_handle, total_elapsed_time, total_worker_time
	, total_logical_reads, total_logical_writes, total_clr_time
	, execution_count, statement_start_offset
	, statement_end_offset, last_execution_time
INTO #PostWorkQuerySnapShot
FROM sys.dm_exec_query_stats

SELECT
	p2.total_elapsed_time - ISNULL(p1.total_elapsed_time, 0) AS [Duration]
	, p2.total_worker_time - ISNULL(p1.total_worker_time, 0) AS [Time on CPU]
	, (p2.total_elapsed_time - ISNULL(p1.total_elapsed_time, 0))
		- (p2.total_worker_time - ISNULL(p1.total_worker_time, 0)) AS [Time waiting]
	, p2.total_logical_reads - ISNULL(p1.total_logical_reads, 0) AS [Reads]
	, p2.total_logical_writes - ISNULL(p1.total_logical_writes, 0) AS [Writes]
	, p2.total_clr_time - ISNULL(p1.total_clr_time, 0) AS [CLR time]
	, p2.execution_count - ISNULL(p1.execution_count, 0) AS [Executions]
	, p2.last_execution_time
	, SUBSTRING (qt.text,p2.statement_start_offset/2 + 1,
	((CASE WHEN p2.statement_end_offset = -1
		THEN LEN(CONVERT(NVARCHAR(MAX), qt.text)) * 2
		ELSE p2.statement_end_offset
	END - p2.statement_start_offset)/2) + 1) AS [Individual Query]
	, qt.text AS [Parent Query]
	, DB_NAME(qt.dbid) AS DatabaseName
FROM #PreWorkQuerySnapShot p1
RIGHT OUTER JOIN
#PostWorkQuerySnapShot p2
		ON p2.sql_handle = ISNULL(p1.sql_handle, p2.sql_handle)
	AND p2.plan_handle = ISNULL(p1.plan_handle, p2.plan_handle)
	AND p2.statement_start_offset = ISNULL(p1.statement_start_offset, p2.statement_start_offset)
	AND p2.statement_end_offset = ISNULL(p1.statement_end_offset, p2.statement_end_offset)
CROSS APPLY sys.dm_exec_sql_text(p2.sql_handle) as qt
WHERE p2.execution_count != ISNULL(p1.execution_count, 0)
ORDER BY DatabaseName, [Parent Query], p2.statement_start_offset

DROP TABLE #PreWorkQuerySnapShot
DROP TABLE #PostWorkQuerySnapShot


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值