SQL - SQL SERVER Performance, Tuning, Monitoring, Analysis and Configuration


Here is list of Performance, Tuning, Monitoring, Analysis and Configuration SQL that help SQL SERVER DBA.


      -- HIGH CPU *******
      --  Who is running what at this instant
      SELECT st.text AS [Command text], login_time, [host_name],
      [program_name], sys.dm_exec_requests.session_id, client_net_address,
      sys.dm_exec_requests.status, command, db_name(database_id) AS DatabaseName
      FROM sys.dm_exec_requests
      INNER JOIN sys.dm_exec_connections
      ON sys.dm_exec_requests.session_id = sys.dm_exec_connections.session_id
      INNER JOIN sys.dm_exec_sessions
      ON sys.dm_exec_sessions.session_id = sys.dm_exec_requests.session_id
      CROSS APPLY sys.dm_exec_sql_text(sql_handle) AS st
      WHERE sys.dm_exec_requests.session_id >= 51
      AND sys.dm_exec_requests.session_id <> @@spid
      ORDER BY sys.dm_exec_requests.status
--show cursor

select c.session_id, c.properties, c.reads, c.writes, c.creation_time, is_open,
substring(qt.text,c.statement_start_offset/2,
(case when c.statement_end_offset = -1
then len(convert(nvarchar(max), qt.text)) * 2
else c.statement_end_offset end - c.statement_start_offset)/2)
as cursor_text
from sys.dm_exec_cursors (0) c
cross apply sys.dm_exec_sql_text(c.sql_handle) qt
where is_open=0

sp_configure
--kill 160

--This example returns information about cursors that have been open on the server longer than the specified time of xx min.

SELECT creation_time, cursor_id, name, c.session_id, login_name
FROM sys.dm_exec_cursors(0) AS c
JOIN sys.dm_exec_sessions AS s ON c.session_id = s.session_id
WHERE DATEDIFF(mi, c.creation_time, GETDATE()) > 1;
GO
--space allocation information for the files associated with tempdb
SELECT
SUM (user_object_reserved_page_count)*8 as usr_obj_kb,
SUM (internal_object_reserved_page_count)*8 as internal_obj_kb,
SUM (version_store_reserved_page_count)*8  as version_store_kb,
SUM (unallocated_extent_page_count)*8 as freespace_kb,
SUM (mixed_extent_page_count)*8 as mixedextent_kb
FROM sys.dm_db_file_space_usage

Select *
from sys.dm_os_performance_counters
WHERE OBJECT_NAME='MSSQL$INSTANCENAME:Buffer Manager'
DBCC memorystatus

SELECT SUM(size)*1.0/128 AS [size in MB]
FROM tempdb.sys.database_files
--pages and memory
SELECT SUM(internal_object_reserved_page_count) AS [internal object pages used],
(SUM(internal_object_reserved_page_count)*1.0/128) AS [internal object space in MB]
FROM sys.dm_db_file_space_usage;

-- top 10 count
SELECT top 10 (total_logical_reads/execution_count),
  (total_logical_writes/execution_count),
  (total_physical_reads/execution_count),
  Execution_count,st.[text],
    qp.query_plan, sql_handle, plan_handle
FROM sys.dm_exec_query_stats  qs
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) st
CROSS APPLY sys.dm_exec_query_plan(qs.plan_handle) qp
ORDER BY (total_logical_reads + total_logical_writes) Desc

-- text of query
SELECT text FROM sys.dm_exec_sql_text (0x02000000A8CDFB26610FE0912D15DE9B57520961A0577BB9)

--showplan
SELECT *
FROM sys.dm_exec_query_plan (0x06000700E4CA3D174043B0AA030000000000000000000000)

-- identify latches wait in tempdb
SELECT *
FROM sys.sysprocesses 
WHERE lastwaittype like 'PAGE%LATCH_%' AND waitresource like '2:%'

SELECT session_id, wait_duration_ms, resource_description
FROM sys.dm_os_waiting_tasks
WHERE wait_type like 'PAGE%LATCH_%' AND resource_description like '7:%'
sp_who2

DBCC PAGE (7,3,23918903)

--Once you know the page number, find the type of the page and the object it belongs to.
--If you see the contention in PFS, GAM or SGAM pages, it implies contention in allocation structures.

SELECT P.object_id, object_name(P.object_id) as object_name,
       P.index_id, BD.page_type
FROM  sys.dm_os_buffer_descriptors BD, sys.allocation_units A,
      sys.partitions P
WHERE  BD.allocation_unit_id = A.allocation_unit_id and 
       A.container_id = P.partition_id



--You can use the following DMV query to find currently pending I/O requests. You can execute this query periodically to check the health of I/O subsystem
and to isolate physical disk(s) that are involved in the I/O bottlenecks.


SELECT
    database_id,
    file_id,
    io_stall,
    io_pending_ms_ticks,
    scheduler_address
FROM   
    sys.dm_io_virtual_file_stats(NULL, NULL)t1
INNER JOIN
       sys.dm_io_pending_io_requests as t2
ON    t1.file_handle = t2.io_handle

--show datafile name and number
SELECT mf.physical_name,* FROM sys.dm_io_virtual_file_stats(NULL, NULL) vfs, sys.master_files mf
where mf.database_id=vfs.database_id and mf.file_id=vfs.file_id and vfs.database_id=7

--If you find, that you regularly have a high number of pending I/O requests, you can use the following query to determine which SQL batches use the most
I/O.




SELECT TOP 5
    (total_logical_reads/execution_count) as avg_logical_reads,
    (total_logical_writes/execution_count) as avg_logical_writes,
    (total_physical_reads/execution_count) as avg_phys_reads,
     Execution_count,
    statement_start_offset as stmt_start_offset,
    st.[text],
    qp.query_plan
FROM sys.dm_exec_query_stats  qs
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) st
CROSS APPLY sys.dm_exec_query_plan(qs.plan_handle) qp
ORDER BY
 (total_logical_reads + total_logical_writes) Desc


--If you are troubleshooting blocked I/O realtime, you can use dm_tran_locks and dm_waiting_tasks to determine what sql is blocking and what is waiting.

SELECT DISTINCT TOP 10
t.TEXT QueryName,
s.execution_count AS ExecutionCount,
s.max_elapsed_time AS MaxElapsedTime,
s.creation_time AS LogCreatedOn
FROM sys.dm_exec_query_stats s
CROSS APPLY sys.dm_exec_sql_text( s.sql_handle ) t
ORDER BY
s.max_elapsed_time DESC
GO



SELECT
    t1.resource_type,
    'database'=db_name(resource_database_id),
    'blk object' = t1.resource_associated_entity_id,
    t1.request_mode,
    t1.request_session_id,
    t2.blocking_session_id    
FROM
    sys.dm_tran_locks as t1
INNER JOIN
    sys.dm_os_waiting_tasks as t2
ON
    t1.lock_owner_address = t2.resource_address and
    t1.request_session_id = t1.request_session_id



--The last thing to check when analyzing I/O is the utlization of tempDB.  You can use dm_db_file_space_usage to determine the amount of space that is being
used in tempdb by user_objects, internal_objects and the version_store.




SELECT
    SUM (user_object_reserved_page_count)*8 as user_objects_kb,
    SUM (internal_object_reserved_page_count)*8 as internal_objects_kb,
    SUM (version_store_reserved_page_count)*8  as version_store_kb,
    SUM (unallocated_extent_page_count)*8 as freespace_kb
FROM sys.dm_db_file_space_usage
WHERE database_id = 2

--fast forward cursor
--DBCC SHOWCONTIG (TableName)
--sp_spaceused TableName
--sp_help TableName



SET IO_STATISTICS ON

select *
from sys.dm_exec_cursors (232) c
cross apply sys.dm_exec_sql_text(c.sql_handle) qt

SELECT cpu_count AS [Logical CPU Count], hyperthread_ratio AS [Hyperthread Ratio],
cpu_count/hyperthread_ratio AS [Physical CPU Count],
physical_memory_in_bytes/1048576 AS [Physical Memory (MB)]
FROM sys.dm_os_sys_info


-- Clear Wait Stats
-- DBCC SQLPERF('sys.dm_os_wait_stats', CLEAR);

-- Isolate top waits for server instance since last restart or statistics clear
WITH Waits AS
(SELECT wait_type, wait_time_ms / 1000. AS wait_time_s,
    100. * wait_time_ms / SUM(wait_time_ms) OVER() AS pct,
    ROW_NUMBER() OVER(ORDER BY wait_time_ms DESC) AS rn
 FROM sys.dm_os_wait_stats
 WHERE wait_type NOT IN( 'SLEEP_TASK', 'BROKER_TASK_STOP',
  'SQLTRACE_BUFFER_FLUSH', 'CLR_AUTO_EVENT', 'CLR_MANUAL_EVENT',
  'LAZYWRITER_SLEEP')) -- filter out additional irrelevant waits
SELECT W1.wait_type,
  CAST(W1.wait_time_s AS DECIMAL(12, 2)) AS wait_time_s,
  CAST(W1.pct AS DECIMAL(12, 2)) AS pct,
  CAST(SUM(W2.pct) AS DECIMAL(12, 2)) AS running_pct
FROM Waits AS W1
INNER JOIN Waits AS W2
ON W2.rn <= W1.rn
GROUP BY W1.rn, W1.wait_type, W1.wait_time_s, W1.pct
HAVING SUM(W2.pct) - W1.pct < 95; -- percentage threshold


-- Signal Waits for instance
SELECT CAST(100.0 * SUM(signal_wait_time_ms) / SUM (wait_time_ms) AS NUMERIC(20,2)) AS [%signal (cpu) waits],
       CAST(100.0 * SUM(wait_time_ms - signal_wait_time_ms) / SUM (wait_time_ms) AS NUMERIC(20,2)) AS [%resource waits]
FROM sys.dm_os_wait_stats;

-- Get CPU Utilization History (SQL 2005 Only)
DECLARE @ts_now bigint;
SELECT @ts_now = cpu_ticks / CONVERT(float, cpu_ticks_in_ms) FROM sys.dm_os_sys_info;

SELECT TOP(30) SQLProcessUtilization AS [SQL Server Process CPU Utilization],
               SystemIdle AS [System Idle Process],
               100 - SystemIdle - SQLProcessUtilization AS [Other Process CPU Utilization],
               DATEADD(ms, -1 * (@ts_now - [timestamp]), GETDATE()) AS [Event Time]
FROM (
      SELECT record.value('(./Record/@id)[1]', 'int') AS record_id,
            record.value('(./Record/SchedulerMonitorEvent/SystemHealth/SystemIdle)[1]', 'int')
            AS [SystemIdle],
            record.value('(./Record/SchedulerMonitorEvent/SystemHealth/ProcessUtilization)[1]',
            'int')
            AS [SQLProcessUtilization], [timestamp]
      FROM (
            SELECT [timestamp], CONVERT(xml, record) AS [record]
            FROM sys.dm_os_ring_buffers
            WHERE ring_buffer_type = N'RING_BUFFER_SCHEDULER_MONITOR'
            AND record LIKE '%<SystemHealth>%') AS x
      ) AS y
ORDER BY record_id DESC;


-- Signal Waits above 10-15% is usually a sign of CPU pressure


-- Page Life Expectancy (PLE) value for default instance
SELECT cntr_value AS [Page Life Expectancy]
FROM sys.dm_os_performance_counters
WHERE OBJECT_NAME = 'MSSQL$INSTANCENAME:Buffer Manager' -- Modify this if you have named instances   'SQLServer:Buffer Manager'
AND counter_name = 'Page life expectancy';

-- PLE is a good measurement of memory pressure
-- Higher PLE is better. Below 300 is generally bad.
-- Watch the trend, not the absolute value

dbcc showfilestats

-- Individual File Sizes and space available for current database
SELECT name AS [File Name] , physical_name AS [Physical Name], size/128 AS [Total Size in MB],
size/128.0 - CAST(FILEPROPERTY(name, 'SpaceUsed') AS int)/128.0 AS [Available Space In MB]
FROM sys.database_files;


--DBCC SHRINKFILE(N'SYSlog',1)

-- Cached SP's By Execution Count (SQL 2005)
SELECT TOP(25) qt.[text] AS [SP Name], qs.execution_count AS [Execution Count], 
qs.execution_count/DATEDIFF(Second, qs.creation_time, GETDATE()) AS [Calls/Second],
qs.total_worker_time/qs.execution_count AS [AvgWorkerTime],
qs.total_worker_time AS [TotalWorkerTime],
qs.total_elapsed_time/qs.execution_count AS [AvgElapsedTime],
qs.max_logical_reads, qs.max_logical_writes, qs.total_physical_reads,
DATEDIFF(Minute, qs.creation_time, GetDate()) AS [Age in Cache]
FROM sys.dm_exec_query_stats AS qs
CROSS APPLY sys.dm_exec_sql_text(qs.[sql_handle]) AS qt
WHERE qt.[dbid] = DB_ID() -- Filter by current database
ORDER BY qs.execution_count DESC;


-- Cached SP's By Worker Time (SQL 2005) Worker time relates to CPU cost
SELECT TOP(25) qt.[text] AS [SP Name], qs.total_worker_time AS [TotalWorkerTime],
qs.total_worker_time/qs.execution_count AS [AvgWorkerTime],
qs.execution_count AS [Execution Count],
ISNULL(qs.execution_count/DATEDIFF(Second, qs.creation_time, GETDATE()), 0) AS [Calls/Second],
ISNULL(qs.total_elapsed_time/qs.execution_count, 0) AS [AvgElapsedTime],
qs.max_logical_reads, qs.max_logical_writes,
DATEDIFF(Minute, qs.creation_time, GETDATE()) AS [Age in Cache]
FROM sys.dm_exec_query_stats AS qs
CROSS APPLY sys.dm_exec_sql_text(qs.[sql_handle]) AS qt
WHERE qt.[dbid] = DB_ID() -- Filter by current database
ORDER BY qs.total_worker_time DESC;

-- Cached SP's By Logical Reads (SQL 2005) Logical reads relate to memory pressure
SELECT TOP(25) qt.[text] AS [SP Name], total_logical_reads,
qs.execution_count AS [Execution Count], total_logical_reads/qs.execution_count AS [AvgLogicalReads],
qs.execution_count/DATEDIFF(Second, qs.creation_time, GETDATE()) AS [Calls/Second],
qs.total_worker_time/qs.execution_count AS [AvgWorkerTime],
qs.total_worker_time AS [TotalWorkerTime],
qs.total_elapsed_time/qs.execution_count AS [AvgElapsedTime],
qs.total_logical_writes,
qs.max_logical_reads, qs.max_logical_writes, qs.total_physical_reads,
DATEDIFF(Minute, qs.creation_time, GETDATE()) AS [Age in Cache]
FROM sys.dm_exec_query_stats AS qs
CROSS APPLY sys.dm_exec_sql_text(qs.[sql_handle]) AS qt
WHERE qt.[dbid] = DB_ID() -- Filter by current database
ORDER BY total_logical_reads DESC;


-- Possible Bad Indexes (writes > reads)
SELECT OBJECT_NAME(s.[object_id]) AS [Table Name], i.name AS [Index Name], i.index_id,
        user_updates AS [Total Writes], user_seeks + user_scans + user_lookups AS [Total Reads],
        user_updates - (user_seeks + user_scans + user_lookups) AS [Difference]
FROM sys.dm_db_index_usage_stats AS s WITH (NOLOCK)
INNER JOIN sys.indexes AS i WITH (NOLOCK)
ON s.[object_id] = i.[object_id]
AND i.index_id = s.index_id
WHERE OBJECTPROPERTY(s.[object_id],'IsUserTable') = 1
AND s.database_id = DB_ID()
AND user_updates > (user_seeks + user_scans + user_lookups)
AND i.index_id > 1
ORDER BY [Difference] DESC, [Total Writes] DESC, [Total Reads] ASC;


-- Missing Indexes for entire instance by Index Advantage
SELECT user_seeks * avg_total_user_cost * (avg_user_impact * 0.01) AS [index_advantage], migs.last_user_seek,
mid.[statement] AS [Database.Schema.Table],
mid.equality_columns, mid.inequality_columns, mid.included_columns,
migs.unique_compiles, migs.user_seeks, migs.avg_total_user_cost, migs.avg_user_impact
FROM sys.dm_db_missing_index_group_stats AS migs WITH (NOLOCK)
INNER JOIN sys.dm_db_missing_index_groups AS mig WITH (NOLOCK)
ON migs.group_handle = mig.index_group_handle
INNER JOIN sys.dm_db_missing_index_details AS mid WITH (NOLOCK)
ON mig.index_handle = mid.index_handle
ORDER BY index_advantage DESC;
--CHECKPOINT 10
--DBCC DROPCLEANBUFFERS
--DBCC FREESYSTEMCACHE ('ALL') WITH MARK_IN_USE_FOR_REMOVAL
-- Breaks down buffers used by current database by object (table, index) in the buffer cache
SELECT OBJECT_NAME(p.[object_id]) AS [ObjectName], p.[object_id],
p.index_id, COUNT(*)/128 AS [buffer size(MB)],  COUNT(*) AS [buffer_count]
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
ON a.container_id = p.hobt_id
WHERE b.database_id = DB_ID()
AND p.[object_id] > 100
GROUP BY p.[object_id], p.index_id
ORDER BY buffer_count DESC;

-- Tells you what tables and indexes are using the most memory in the buffer cache
SELECT * FROM  sys.dm_os_sys_info
select * from sys.dm_os_threads

-- Detect blocking (run multiple times)
SELECT t1.resource_type AS [lock type],DB_NAME(resource_database_id) AS [database],
t1.resource_associated_entity_id AS [blk object],t1.request_mode AS [lock req],                                                                          ---
lock requested
t1.request_session_id AS [waiter sid], t2.wait_duration_ms AS [wait time], -- spid of waiter 
(SELECT [text] FROM sys.dm_exec_requests AS r                              -- get sql for waiter
CROSS APPLY sys.dm_exec_sql_text(r.[sql_handle])
WHERE r.session_id = t1.request_session_id) AS [waiter_batch],
(SELECT SUBSTRING(qt.[text],r.statement_start_offset/2,
    (CASE WHEN r.statement_end_offset = -1
    THEN LEN(CONVERT(nvarchar(max), qt.[text])) * 2
    ELSE r.statement_end_offset END - r.statement_start_offset)/2)
FROM sys.dm_exec_requests AS r
CROSS APPLY sys.dm_exec_sql_text(r.[sql_handle]) AS qt
WHERE r.session_id = t1.request_session_id) AS [waiter_stmt],    -- statement blocked
t2.blocking_session_id AS [blocker sid],                         -- spid of blocker
(SELECT [text] FROM sys.sysprocesses AS p                        -- get sql for blocker
CROSS APPLY sys.dm_exec_sql_text(p.[sql_handle])
WHERE p.spid = t2.blocking_session_id) AS [blocker_stmt]
FROM sys.dm_tran_locks AS t1
INNER JOIN sys.dm_os_waiting_tasks AS t2
ON t1.lock_owner_address = t2.resource_address;



-- HIGH CPU *******
    -- Get the most CPU intensive queries
    SET NOCOUNT ON;

    DECLARE @spID smallint
    DECLARE spID_Cursor CURSOR
    FAST_FORWARD FOR
   
    SELECT TOP 25 spid
    FROM master..sysprocesses
    WHERE status = 'runnable'
    AND spid > 50   -- Eliminate system SPIDs
    AND spid <> @@SPID
    ORDER BY CPU DESC

    OPEN spID_Cursor

    FETCH NEXT FROM spID_Cursor
    INTO @spID
        WHILE @@FETCH_STATUS = 0
        BEGIN
            PRINT 'Spid #:' + STR(@spID)
            EXEC ('DBCC INPUTBUFFER (' + @spID + ')')

               FETCH NEXT FROM spID_Cursor
            INTO @spID
        END

    -- Close and deallocate the cursor
    CLOSE spID_Cursor
    DEALLOCATE spID_Cursor


 -- HIGH CPU *******
      -- Isolate top waits for server instance
--DBCC SQLPERF(WAITSTATS, CLEAR)   

  WITH Waits AS
      (
        SELECT
            wait_type,
            wait_time_ms / 1000. AS wait_time_s,
            100. * wait_time_ms / SUM(wait_time_ms) OVER() AS pct,
            ROW_NUMBER() OVER(ORDER BY wait_time_ms DESC) AS rn
        FROM sys.dm_os_wait_stats
        WHERE wait_type NOT LIKE '%SLEEP%'
      )
      SELECT
        W1.wait_type,
        CAST(W1.wait_time_s AS DECIMAL(12, 2)) AS wait_time_s,
        CAST(W1.pct AS DECIMAL(12, 2)) AS pct,
        CAST(SUM(W2.pct) AS DECIMAL(12, 2)) AS running_pct
      FROM Waits AS W1
      INNER JOIN Waits AS W2
      ON W2.rn <= W1.rn
      GROUP BY W1.rn, W1.wait_type, W1.wait_time_s, W1.pct
      HAVING SUM(W2.pct) - W1.pct < 90 -- percentage threshold
      ORDER BY W1.rn;

--exec sp_configure 'default trace enabled',0
--reconfigure

select * from sys.dm_os_waiting_tasks
where wait_type = 'SQLTRACE_BUFFER_FLUSH'



--CHECKPOINT
--DBCC TRACEON(3502, -1) --turn on checkpoint logging

--DBCC TRACEOFF(3502, -1) --turn off checkpoint logging

--EXEC xp_readerrorlog --read the log

--sp_configure
-- HIGH CPU *******
      -- Total waits are wait_time_ms (high signal waits indicates CPU pressure)
      SELECT '%signal (cpu) waits' = CAST(100.0 * SUM(signal_wait_time_ms) / SUM (wait_time_ms) AS NUMERIC(20,2)),
           '%resource waits'= CAST(100.0 * SUM(wait_time_ms - signal_wait_time_ms) / SUM (wait_time_ms) AS NUMERIC(20,2))
      FROM sys.dm_os_wait_stats;

      -- HIGH CPU *******
      -- Check SQL Server Schedulers to see if they are waiting on CPU (runnable tasks above 10 is very bad)
      SELECT scheduler_id, current_tasks_count, runnable_tasks_count
      FROM sys.dm_os_schedulers
      WHERE scheduler_id < 255


--Analyzing SQL SERVER 2005 LONG RUNNING QUERIES
select name,Page_verify_option_desc from sys.databases

SELECT r.session_id as sid,
 s.HOST_NAME,  r.status, r.wait_time,wait_type,r.logical_reads as logical_r, r.wait_resource,SUBSTRING(qt.text,(r.statement_start_offset/2) +1,
(CASE WHEN r.statement_end_offset = -1 THEN LEN(CONVERT(nvarchar(max), qt.text)) * 2 ELSE r.statement_end_offset END -r.statement_start_offset)/2)
AS stmt_executing,r.blocking_session_id as blk_sid,r.cpu_time,r.total_elapsed_time as tol_elp_tm,r.reads,r.writes,
r.plan_handle,s.host_process_id,s.PROGRAM_NAME FROM sys.dm_exec_requests r
CROSS APPLY sys.dm_exec_sql_text(sql_handle) as qt, sys.dm_exec_sessions s
WHERE r.session_id > 50 and r.session_id=s.session_id and r.session_id <> @@spid ORDER BY sid  desc --r.session_id, s.host_name, s.program_name, r.status



-- Get a snapshot of current activity
      SELECT LTRIM (st.text) AS 'Command Text',[host_name], der.session_id AS 'SPID',
      der.status, db_name(database_id) AS DatabaseName, ISNULL(der.wait_type, 'None')AS 'Wait Type', der.logical_reads
      FROM sys.dm_exec_requests AS der
      INNER JOIN sys.dm_exec_connections AS dexc
      ON der.session_id = dexc.session_id
      INNER JOIN sys.dm_exec_sessions AS dexs
      ON dexs.session_id = der.session_id
      CROSS APPLY sys.dm_exec_sql_text(sql_handle) AS st
      WHERE der.session_id >= 51
      AND der.session_id <> @@spid
      ORDER BY der.logical_reads desc
--kill 73

sp_who2 160

dbcc traceon (3604)
DBCC PAGE (7,4,1560834)
dbcc traceoff (3604)
SELECT OBJECT_NAME (1566172875)
DBCC EXTENTINFO(0, TABLENAME, -1)


-- the formatting seems to be working for me, and this is so useful!

/* The following query automates the process of translating the page in a waitresource in sysprocesses (of the form dbid:fileid:page) into the object name
containing that page. */
SET NOCOUNT ON declare @dbid int, @fileid int, @pageid int, @spid int, @sql varchar(128)
--set your spid of interest here:
set @spid = 197
select @dbid = substring(waitresource, 1, charindex (':', waitresource) - 1),
   @fileid = substring(waitresource, charindex( ':', waitresource) + 1,
      charindex(':', waitresource, charindex(':', waitresource) + 1) -
      charindex(':',waitresource) - 1 ),
   @pageid = substring(waitresource, charindex(':', waitresource,
      charindex(':', waitresource, charindex(':', waitresource) + 1)) + 1,
      len(waitresource) - (charindex(':', waitresource,
      charindex(':', waitresource, charindex(':', waitresource) + 1)) + 1) )
from master..sysprocesses where spid = @spid and waitresource like '%:%:%'
set @sql = 'dbcc page (' + convert(varchar,@dbid) + ',' +
   convert(varchar,@fileid) + ',' + convert(varchar,@pageid) + ') with
   no_infomsgs, tableresults'
if exists (select 1 from tempdb..sysobjects where xtype = 'U' and name like
   '#pageinfo%')
   drop table #pageinfo
create table #pageinfo ( ParentObject varchar(128), Object varchar(128),
   Field varchar(128), Value varchar(128) )
dbcc traceon (3604) with no_infomsgs
   insert into #pageinfo (ParentObject, Object, Field, Value)
exec (@sql) select object_name(Value) as 'waitresource object name' from
   #pageinfo where Field = 'm_objId' dbcc traceoff (3604) with no_infomsgs

-- BLOCKING ************
      -- Detect blocking
      SELECT blocked_query.session_id AS blocked_session_id,
      blocking_query.session_id AS blocking_session_id,
      sql_text.text AS blocked_text, sql_btext.text AS blocking_text, waits.wait_type AS blocking_resource
      FROM sys.dm_exec_requests AS blocked_query
      INNER JOIN sys.dm_exec_requests AS blocking_query
      ON blocked_query.blocking_session_id = blocking_query.session_id
      CROSS APPLY
      (SELECT * FROM sys.dm_exec_sql_text(blocking_query.sql_handle)
      ) sql_btext
      CROSS APPLY
      (SELECT * FROM sys.dm_exec_sql_text(blocked_query.sql_handle)
      ) sql_text
      INNER JOIN sys.dm_os_waiting_tasks AS waits
      ON waits.session_id = blocking_query.session_id

      -- BLOCKING ************
      -- Index Contention
      SELECT dbid=database_id, objectname=object_name(s.object_id),
      indexname=i.name, i.index_id, row_lock_count, row_lock_wait_count,
      [block %]= CAST (100.0 * row_lock_wait_count / (1 + row_lock_count) AS NUMERIC(15,2)),
      row_lock_wait_in_ms,
      [avg row lock waits in ms]= CAST (1.0 * row_lock_wait_in_ms / (1 + row_lock_wait_count) AS NUMERIC(15,2))
      FROM sys.dm_db_index_operational_stats (db_id(), NULL, NULL, NULL) AS s
      INNER JOIN sys.indexes AS i
      ON i.object_id = s.object_id
      WHERE objectproperty(s.object_id,'IsUserTable') = 1
      AND i.index_id = s.index_id
      ORDER BY row_lock_wait_count DESC

      -- TRANSACTION LOG FULL *****
      -- Find the log reuse description for the transaction log
      SELECT name, database_id, log_reuse_wait_desc
      FROM sys.databases

-- TRANSACTION LOG FULL *****


      -- IO ISSUES *****************
      -- Analyze DB IO, ranked by IO Stall %
      WITH DBIO AS
      (
        SELECT
            DB_NAME(IVFS.database_id) AS db,
            CASE WHEN MF.type = 1 THEN 'log' ELSE 'data' END AS file_type,
            SUM(IVFS.num_of_bytes_read + IVFS.num_of_bytes_written) AS io,
            SUM(IVFS.io_stall) AS io_stall
        FROM sys.dm_io_virtual_file_stats(NULL, NULL) AS IVFS
            JOIN sys.master_files AS MF
              ON IVFS.database_id = MF.database_id
              AND IVFS.file_id = MF.file_id
        GROUP BY DB_NAME(IVFS.database_id), MF.type
      )
      SELECT db, file_type,
        CAST(1. * io / (1024 * 1024) AS DECIMAL(12, 2)) AS io_mb,
        CAST(io_stall / 1000. AS DECIMAL(12, 2)) AS io_stall_s,
        CAST(100. * io_stall / SUM(io_stall) OVER()
               AS DECIMAL(10, 2)) AS io_stall_pct,
        ROW_NUMBER() OVER(ORDER BY io_stall DESC) AS rn
      FROM DBIO
      ORDER BY io_stall DESC;
SELECT * FROM sys.dm_io_virtual_file_stats(DB_ID(N'DBNAME'), 1);
--kill 105

-- Get Top 100 executed SP's ordered by execution count
      SELECT TOP 100 qt.text AS 'SP Name', qs.execution_count AS 'Execution Count', 
      qs.execution_count/DATEDIFF(Second, qs.creation_time, GetDate()) AS 'Calls/Second',
      qs.total_worker_time/qs.execution_count AS 'AvgWorkerTime',
      qs.total_worker_time AS 'TotalWorkerTime',
      qs.total_elapsed_time/qs.execution_count AS 'AvgElapsedTime',
      qs.max_logical_reads, qs.max_logical_writes, qs.total_physical_reads,
      DATEDIFF(Minute, qs.creation_time, GetDate()) AS 'Age in Cache'
      FROM sys.dm_exec_query_stats AS qs
      CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) AS qt
      WHERE qt.dbid = db_id() -- Filter by current database
      ORDER BY qs.execution_count DESC

      -- HIGH CPU *************
      -- Get Top 20 executed SP's ordered by total worker time (CPU pressure)
      SELECT TOP 20 qt.text AS 'SP Name', qs.total_worker_time AS 'TotalWorkerTime',
      qs.total_worker_time/qs.execution_count AS 'AvgWorkerTime',
      qs.execution_count AS 'Execution Count',
      ISNULL(qs.execution_count/DATEDIFF(Second, qs.creation_time, GetDate()), 0) AS 'Calls/Second',
      ISNULL(qs.total_elapsed_time/qs.execution_count, 0) AS 'AvgElapsedTime',
      qs.max_logical_reads, qs.max_logical_writes,
      DATEDIFF(Minute, qs.creation_time, GetDate()) AS 'Age in Cache'
      FROM sys.dm_exec_query_stats AS qs
      CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) AS qt
      WHERE qt.dbid = db_id() -- Filter by current database
      ORDER BY qs.total_worker_time DESC
-- find plan for sql
select qs.execution_count,
      t.text,
      p.query_plan,
      qs.creation_time,
      qs.last_execution_time,
      qs.last_elapsed_time,
      qs.min_elapsed_time ,
      qs.max_elapsed_time ,
      qs.total_elapsed_time /qs.execution_count as 'Avg Execution_time',
      qs.plan_handle,
      qs.sql_handle
from sys.dm_exec_query_stats qs
cross apply sys.dm_exec_sql_text(qs.sql_handle) t
cross apply sys.dm_exec_query_plan(qs.plan_handle) p
where t.text like '%TABLENAME%'

-- check duplicate plan exist
select t.text from sys.dm_exec_query_stats qs
cross apply sys.dm_exec_sql_text(qs.sql_handle) t
cross apply sys.dm_exec_query_plan(qs.plan_handle) p
group by t.text
having COUNT(t.text) >1


--show cached plans
SELECT [cp].[refcounts]
, [cp].[usecounts]
, [cp].[objtype]
, [st].[dbid]
, [st].[objectid]
, [st].[text]
, [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 ;



-- query demonstrates how the dynamic management view returns fragmentation information:
SELECT database_id,object_id, index_id, index_type_desc, index_depth, index_level, avg_fragmentation_in_percent, fragment_count, avg_fragment_size_in_pages
FROM sys.dm_db_index_physical_stats
(DB_ID(N'DBNAME'), OBJECT_ID(N'TableName'), NULL, NULL , NULL);
--UPDATE STATISTICS TableName
--For PeopleSoft applications, the value for avg_fragmentation_in_percent should ideally be as close to zero as possible for
--maximum performance. However, values from 0 percent through 10 percent may be acceptable.


select spid,physical_io fio
into #f
from master..sysprocesses where spid > 50

waitfor delay '00:00:02'

select s.spid,fio,physical_io,physical_io-fio used
from master..sysprocesses s join #f on s.spid = #f.spid
where s.spid > 50
order by physical_io - fio desc

drop table #f




select * from sys.dm_os_tasks
select * from sys.dm_os_schedulers
select * from sys.dm_os_waiting_tasks
select * from sys.dm_os_threads
select * from sys.dm_os_workers
select * from sys.dm_os_sys_info
select * from sys.dm_exec_connections where auth_scheme='NTLM'

select * from sys.tcp_endpoints


SELECT * FROM sys.dm_os_ring_buffers
WHERE ring_buffer_type =
'RING_BUFFER_MEMORY_BROKER';

SELECT type, /*sum(multi_pages_kb) ,*/ *
FROM sys.dm_os_memory_clerks
WHERE multi_pages_kb != 0


SELECT type, sum(multi_pages_kb)
FROM sys.dm_os_memory_clerks
WHERE multi_pages_kb != 0
GROUP BY type;


SELECT type, sum(multi_pages_kb)
FROM sys.dm_os_memory_cache_counters
WHERE multi_pages_kb != 0
GROUP BY type;