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

 

 

你可能感兴趣的:(sql)