SQL 維護用得到的監控語句

使用DMV來分析SQL Server啓動以來累計使用CPU資源最多的語句。例如下面的語句就可以列出前50名

SELECT TOP 50 s2.dbid, 
    (SELECT TOP 1 SUBSTRING(s2.text,statement_start_offset / 2+1 , 
      ( (CASE WHEN statement_end_offset = -1 
         THEN (LEN(CONVERT(nvarchar(max),s2.text)) * 2) 
         ELSE statement_end_offset END)  - statement_start_offset) / 2+1))  AS sql_statement,
    execution_count,     plan_generation_num,     last_execution_time,       total_worker_time,     

last_worker_time,     min_worker_time, 
    max_worker_time,    total_physical_reads,     last_physical_reads, 
    min_physical_reads,      max_physical_reads,      total_logical_writes,     last_logical_writes,     

min_logical_writes,     max_logical_writes
FROM sys.dm_exec_query_stats AS s1 
CROSS APPLY sys.dm_exec_sql_text(sql_handle) AS s2  
WHERE s2.objectid is null
ORDER BY s1.total_worker_time desc

--第二種
select  c.last_execution_time,c.execution_count,c.total_logical_reads,
c.total_logical_writes,c.total_elapsed_time,c.last_elapsed_time,q.[text]
from  (select top 50 qs.*    from sys.dm_exec_query_stats qs    
order by qs.total_worker_time desc) as c    
cross apply sys.dm_exec_sql_text(plan_handle) 
as q order by c.total_worker_time desc 

返回最經常運行的100條語句

SELECT TOP 100 cp.cacheobjtype,cp.usecounts,cp.size_in_bytes,
qs.statement_start_offset,qs.statement_end_offset,qt.dbid 
,qt.objectid  
,SUBSTRING(qt.text,qs.statement_start_offset/2, 
  (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) 
    as statement FROM sys.dm_exec_query_stats qs 
    cross apply sys.dm_exec_sql_text(qs.sql_handle) as qt 
    inner join sys.dm_exec_cached_plans as cp on qs.plan_handle=cp.plan_handle 
    where cp.plan_handle=qs.plan_handle and cp.usecounts>4 
    ORDER BY [dbid],[Usecounts] DESC

返回做IO數目最多的50條語句以及它們的執行計劃

select top 50 (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, 
statement_end_offset as stmt_end_offset,
substring(sql_text.text, (statement_start_offset/2), 
case when (statement_end_offset -statement_start_offset)/2 <=0 then 64000 
else (statement_end_offset -statement_start_offset)/2 end) as exec_statement, 
 sql_text.text,plan_text.* 
 from sys.dm_exec_query_stats  
 cross apply sys.dm_exec_sql_text(sql_handle) as sql_text
 cross apply sys.dm_exec_query_plan(plan_handle) as plan_text
 order by  (total_logical_reads + total_logical_writes) /Execution_count Desc

計算signal wait佔整wait時間的百分比
指令等待 CPU 資源的時間佔總時間的百分比。如果超過 25% ,說明 CPU 緊張

select convert(numeric(5,4),sum(signal_wait_time_ms)/sum(wait_time_ms)) 
from Sys.dm_os_wait_stats 

計算'Cxpacket'佔整wait時間的百分比
Cxpacket:Sql Server 在處理一句代價很大的語句,要不就是沒有合適的索引或篩選條件沒能篩選足夠的記錄,使得
語句要返回大量的結果,當 >5% 說明有問題

declare @Cxpacket bigint
declare @Sumwaits bigint
select @Cxpacket = wait_time_ms
from Sys.dm_os_wait_stats
where wait_type = 'Cxpacket'
select @Sumwaits = sum(wait_time_ms)
from Sys.dm_os_wait_stats
select convert(numeric(5,4),@Cxpacket/@Sumwaits)

查詢當前數據庫上所有用戶表格在Row lock上發生阻塞的頻率

declare @dbid int
select @dbid = db_id()
Select dbid=database_id, objectname=object_name(s.object_id), 
indexname=i.name, i.index_id    
--, partition_number, 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 (@dbid, NULL, NULL, NULL) s,  
   sys.indexes i where objectproperty(s.object_id,'IsUserTable') = 1
   and i.object_id = s.object_id and i.index_id = s.index_id
   order 
   by row_lock_wait_count desc

返回當前數據庫所有碎片率大於25%的索引
運行本語句會掃描很多數據頁面
避免在系統負載比較高時運行
避免在系統負載比較高時運行

declare @dbid int
select @dbid = db_id()
SELECT o.name as tablename,s.* 
FROM sys.dm_db_index_physical_stats (@dbid, NULL, NULL, NULL, NULL) s,
sys.objects o
where avg_fragmentation_in_percent>25 and o.object_id =s.object_id
order by avg_fragmentation_in_percent desc

當前數據庫可能缺少的索引

select d.*        , s.avg_total_user_cost        , 
s.avg_user_impact        , s.last_user_seek        ,
s.unique_compiles
from sys.dm_db_missing_index_group_stats s        ,
sys.dm_db_missing_index_groups g        ,
sys.dm_db_missing_index_details d
where s.group_handle = g.index_group_handle
and d.index_handle = g.index_handle
order by s.avg_user_impact desc

自動重建或重新組織索引

SET NOCOUNT ON;DECLARE @objectid int;DECLARE @indexid int;DECLARE @partitioncount bigint;
DECLARE @schemaname nvarchar(130); DECLARE @objectname nvarchar(130); 
DECLARE @indexname nvarchar(130); DECLARE @partitionnum bigint;
DECLARE @partitions bigint;DECLARE @frag float;DECLARE @command nvarchar(4000); 
-- Conditionally select tables and indexes from the sys.dm_db_index_physical_stats function 
-- and convert object and index IDs to names.
SELECT    object_id AS objectid,    index_id AS indexid,    partition_number AS partitionnum,    

avg_fragmentation_in_percent AS frag
INTO 
#work_to_do
FROM sys.dm_db_index_physical_stats (DB_ID(),
 NULL, NULL , NULL, 'LIMITED')
 WHERE avg_fragmentation_in_percent > 10.0 AND index_id > 0;
 -- Declare the cursor for the list of partitions to be processed.
 DECLARE partitions CURSOR FOR SELECT * FROM #work_to_do;
 -- Open the cursor.
 OPEN partitions;
 -- Loop through the partitions.
 WHILE (1=1)    
 BEGIN;        FETCH NEXT           FROM partitions          
  INTO @objectid, @indexid, @partitionnum, @frag;    
      IF @@FETCH_STATUS < 0 BREAK;       
       SELECT @objectname = QUOTENAME(o.name), @schemaname = QUOTENAME(s.name)   
            FROM sys.objects AS o        JOIN sys.schemas as s ON s.schema_id = o.schema_id       
             WHERE o.object_id = @objectid;       
              SELECT @indexname = QUOTENAME(name)     
                 FROM sys.indexes      
                   WHERE  object_id = @objectid AND index_id = @indexid;     
                      SELECT @partitioncount = count (*)        FROM sys.partitions  
                            WHERE object_id = @objectid AND index_id = @indexid;
                            -- 30 is an arbitrary decision point at which to switch between reorganizing 

and rebuilding.     
                               IF @frag < 30.0          
                                 SET @command = N'ALTER INDEX ' + @indexname + N' ON ' + @schemaname + 

N'.' + @objectname + N' REORGANIZE';        
                                 IF @frag >= 30.0          
                                   SET @command = N'ALTER INDEX ' + @indexname + N' ON ' + @schemaname + 

N'.' + @objectname + N' REBUILD';       
                                    IF @partitioncount > 1      
                                          SET @command = @command + N' PARTITION=' + CAST(@partitionnum 

AS nvarchar(10));    
                                              EXEC (@command);       
                                               PRINT N'Executed: ' + @command;    END;
                                               -- Close and deallocate the cursor.
                                               CLOSE partitions;
                                               DEALLOCATE partitions;
                                               -- Drop the temporary table.
                                               DROP TABLE #work_to_do;

查看當前數據庫索引的使用率

SELECT
object_name(object_id) as table_name,
(select name from sys.indexes
where object_id = stats.object_id 
and index_id = stats.index_id) 
as index_name,*
FROM sys.dm_db_index_usage_stats 
as stats
WHERE database_id = DB_ID()order by table_name

指定表的索引使用情況

declare @table as nvarchar(100)
set @table = 'Table_1';
SELECT(  select name  from sys.indexes  
where object_id = stats.object_id and index_id = stats.index_id) 
as index_name,*
FROM sys.dm_db_index_usage_stats as stats
where object_id = object_id(@table)
order by user_seeks, user_scans, user_lookups asc

最經常做重編譯的存儲過程

select top 25 sql_text.text, sql_handle, plan_generation_num,  execution_count,

    dbid,  objectid 

from sys.dm_exec_query_stats a

    cross apply sys.dm_exec_sql_text(sql_handle) as sql_text

where plan_generation_num>1

order by plan_generation_num desc

sp_lock 
select OBJECT_NAME(objid)
dbcc inputbuffer(spid) 
select @@spid
kill 58 WITH STATUSONLY
EXEC sp_who 'active'

查詢系統中死鎖的SQL語句

declare @spid int,@bl int,
@intTransactionCountOnEntry     int,
@intRowcount             int,
@intCountProperties         int,
@intCounter             int
create table #tmp_lock_who (
id int identity(1,1),
spid smallint,
bl smallint)
IF @@ERROR<>0 print @@ERROR
insert into #tmp_lock_who(spid,bl) select  0 ,blocked
from (select * from sysprocesses where  blocked>0 ) a
where not exists(select * from (select * from sysprocesses
where  blocked>0 ) b
where a.blocked=spid)
union select spid,blocked from sysprocesses where  blocked>0
IF @@ERROR<>0 print @@ERROR
-- 找到臨時表的記錄數
select     @intCountProperties = Count(*),@intCounter = 1
from #tmp_lock_who
IF @@ERROR<>0 print @@ERROR
if    @intCountProperties=0
select '現在沒有阻塞和死鎖信息' as message
-- 循環開始
while @intCounter <= @intCountProperties
begin
-- 取第一條記錄
select     @spid = spid,@bl = bl
from #tmp_lock_who where Id = @intCounter
begin
if @spid =0
select '引起數據庫死鎖的是: '+ CAST(@bl AS VARCHAR(10))
+ '進程號,其執行的SQL語法如下'
else
select '進程號SPID:'+ CAST(@spid AS VARCHAR(10))+ ''
+ '進程號SPID:'+ CAST(@bl AS VARCHAR(10)) +'阻塞,其當前進程執行的SQL語法如下'
DBCC INPUTBUFFER (@bl )
end
-- 循環指針下移
set @intCounter = @intCounter + 1
end

select * from #tmp_lock_who

drop table #tmp_lock_who

select @@lock_timeout

查看鎖信息

 select   進程id=req_spid   
  ,數據庫=db_name(rsc_dbid)   
  ,類型=case   rsc_type   when   1   then   'NULL   資源(未使用)'   
  when   2   then   '數據庫'   
  when   3   then   '文件'   
  when   4   then   '索引'   
  when   5   then   ''   
  when   6   then   ''   
  when   7   then   ''   
  when   8   then   '擴展盤區'   
  when   9   then   'RID(行   ID)'   
  when   10   then   '應用程序'   
  end   
  ,rsc_objid,rsc_indid   
  from   master..syslockinfo   



select * from sys.dm_tran_locks
SET SHOWPLAN_ALL ON; SET STATISTICS IO on; SET STATISTICS TIME on

列出最初鎖住資源,導致一連串其他進程被鎖住的起始源頭

IF EXISTS(SELECT * FROM master.sys.sysprocesses WHERE spid 
    IN (SELECT blocked FROM master.sys.sysprocesses))    
    --確定有進程被其他的進程鎖住
    SELECT 
         DISTINCT '進程ID' = STR(a.spid, 4)
        ,'進程ID狀態' = CONVERT(CHAR(10), a.status)
        ,'登入帳號'=SUBSTRING(SUSER_SNAME(sid),1,30) 
        ,'工作站名稱' = CONVERT(CHAR(10), a.hostname)
        ,'執行命令的用戶' = CONVERT(CHAR(10), SUSER_NAME(a.uid))
        ,'是否被鎖住'=CONVERT(char(3),blocked)
        ,'數據庫名' = CONVERT(CHAR(10), DB_NAME(a.dbid))
        ,'正在執行的命令' = CONVERT(CHAR(16), a.cmd)
        ,'登錄名' = a.loginame
        ,'執行語句' = b.text
        ,'等待型態' = a.waittype  
    FROM master..sysprocesses a CROSS APPLY sys.dm_exec_sql_text(a.sql_handle) b 
    --列出鎖住別人(在別的進程中 blocked字段出現的值),但自己未被鎖住(blocked=0)
    WHERE spid IN (SELECT blocked FROM master.sys.sysprocesses) 
    AND blocked=0
ELSE
    SELECT 'No Blocked Session(s)'
--a.status = suspended,a.blocked(阻塞者id)
--DBCC INPUTBUFFER (阻塞者id);
--就可以看到語句了或者join

經常出現的是,在sysprocesses視圖中 status是'sleeping',waittype字段是0x0000,打開事務數open_tran大於0,一般
都是交易已經激活但遲遲沒有結束,就可能是程序沒有管理好交易管理

select a.*,b.text
from master.sys.sysprocesses a  
CROSS APPLY sys.dm_exec_sql_text(a.sql_handle) b
where a.status = 'sleeping' and a.waittype=0x0000 and a.open_tran > 0


select t1.resource_type as [資源鎖定類型]
    ,db_name(resource_database_id) as [數據庫名]
    ,t1.resource_associated_entity_id as [鎖定的對象]
    ,t1.request_mode as [等待者需求的鎖定類型]
    ,t1.request_session_id as [等待者sid]  
    ,t2.wait_duration_ms as [等待時間]    
    ,(select text from sys.dm_exec_requests as r  
        cross apply sys.dm_exec_sql_text(r.sql_handle) 
        where r.session_id = t1.request_session_id) as [等待者要執行的批次]
    ,(select substring(qt.text,r.statement_start_offset/2+1, 
            (case when r.statement_end_offset = -1 
            then datalength(qt.text) 
            else r.statement_end_offset end - r.statement_start_offset)/2+1) 
        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 [等待者正要執行的語法]
     ,t2.blocking_session_id as [鎖定者sid] 
     ,(select text from sys.sysprocesses as p        
        cross apply sys.dm_exec_sql_text(p.sql_handle) 
        where p.spid = t2.blocking_session_id) as [鎖定者的語法]
    from 
    sys.dm_tran_locks as t1, 
    sys.dm_os_waiting_tasks as t2
where 
    t1.lock_owner_address = t2.resource_address

統計分析

DBCC SHOW_STATISTICS('表名','索引名')

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章