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('表名','索引名')

 

 

posted @ 2013-07-11 14:43  StupidsCat  阅读(517)  评论(0编辑  收藏  举报