SQL常用性能相关脚本

--调试语句性能前记得清空执行计划

每次执行需优化SQL前,带上清除缓存的设置SQL。

平常在进行SQL Server性能优化时,为了确保真实还原性能问题,我们需要关闭SQL Server自身的执行计划及缓存。可以通过以下设置清除缓存。

1 DBCC DROPCLEANBUFFERS  --清除缓冲区
2 DBCC FREEPROCCACHE  --删除计划高速缓存中的元素

 

开启查询IO读取统计、查询时间统计。

SET STATISTICS TIME ON --执行时间
SET STATISTICS IO ON --IO读取


--查询当前的事务

select 
t2.session_id as SPID,
t2.transaction_id,
transaction_begin_time,
N'已执行'+ltrim(datediff(mi,transaction_begin_time,getdate()))+N'分钟' as mi,
case transaction_type 
when 1 then N'读/写事务' 
when 2 then N'只读事务' 
when 3 then N'系统事务' 
when 4 then N'分布式事务' end tran_Type,
case transaction_state
when 0 then N'事务尚未完全初始化'
when 1 then N'事务已初始化但尚未启动'
when 2 then N'事务处于活动状态'
when 3 then N'事务已结束。该状态用于只读事务'
when 4 then N'已对分布式事务启动提交进程'
when 5 then N'事务处于准备就绪状态且等待解析'
when 6 then N'事务已提交'
when 7 then N'事务正在被回滚'
when 0 then N'事务已回滚'
end transaction_state,
client_net_address,
client_tcp_port,
program_name,
t2.text

from
sys.dm_tran_active_transactions t1 join (
select 
a.session_id,
transaction_id,
client_net_address,
client_tcp_port,
text,c.program_name
from sys.dm_tran_session_transactions a join (
select session_id,a2.text,client_net_address,client_tcp_port from sys.dm_exec_connections a1
cross apply sys.dm_exec_sql_text(a1.most_recent_sql_Handle) a2
) b on a.session_id=b.session_id
left join sys.dm_exec_sessions c on a.session_id=c.session_id
where is_user_transaction=1
)t2 on t1.transaction_ID=t2.transaction_ID
ORDER BY t2.transaction_id
View Code
 
--死锁相关,转自http://www.blogjava.net/parable-myth/archive/2007/10/15/153010.html
if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[p_lockinfo]') and OBJECTPROPERTY(id, N'IsProcedure') = 1)
drop procedure [dbo].[p_lockinfo]
GO

SET QUOTED_IDENTIFIER ON 
GO
SET ANSI_NULLS ON 
GO


/*--处理死锁

 查看当前进程,或死锁进程,并能自动杀掉死进程

 因为是针对死的,所以如果有死锁进程,只能查看死锁进程
 当然,你可以通过参数控制,不管有没有死锁,都只查看死锁进程

 感谢: caiyunxia,jiangopen 两位提供的参考信息

--邹建 2004.4--*/

/*--调用示例

 exec p_lockinfo
--*/
create proc p_lockinfo
@kill_lock_spid bit=1,  --是否杀掉死锁的进程,1 杀掉, 0 仅显示
@show_spid_if_nolock bit=1 --如果没有死锁的进程,是否显示正常进程信息,1 显示,0 不显示
as
declare @count int,@s nvarchar(1000),@i int
select id=identity(int,1,1),标志,
 进程ID=spid,线程ID=kpid,块进程ID=blocked,数据库ID=dbid,
 数据库名=db_name(dbid),用户ID=uid,用户名=loginame,累计CPU时间=cpu,
 登陆时间=login_time,打开事务数=open_tran, 进程状态=status,
 工作站名=hostname,应用程序名=program_name,工作站进程ID=hostprocess,
 域名=nt_domain,网卡地址=net_address
into #t from(
 select 标志='死锁的进程',
  spid,kpid,a.blocked,dbid,uid,loginame,cpu,login_time,open_tran,
  status,hostname,program_name,hostprocess,nt_domain,net_address,
  s1=a.spid,s2=0
 from master..sysprocesses a join (
  select blocked from master..sysprocesses group by blocked
  )b on a.spid=b.blocked where a.blocked=0
 union all
 select '|_牺牲品_>',
  spid,kpid,blocked,dbid,uid,loginame,cpu,login_time,open_tran,
  status,hostname,program_name,hostprocess,nt_domain,net_address,
  s1=blocked,s2=1
 from master..sysprocesses a where blocked<>0
)a order by s1,s2

select @count=@@rowcount,@i=1

if @count=0 and @show_spid_if_nolock=1
begin
 insert #t
 select 标志='正常的进程',
  spid,kpid,blocked,dbid,db_name(dbid),uid,loginame,cpu,login_time,
  open_tran,status,hostname,program_name,hostprocess,nt_domain,net_address
 from master..sysprocesses
 set @count=@@rowcount
end

if @count>0
begin
 create table #t1(id int identity(1,1),a nvarchar(30),b Int,EventInfo nvarchar(255))
 if @kill_lock_spid=1
 begin
  declare @spid varchar(10),@标志 varchar(10)
  while @i<=@count
  begin
   select @spid=进程ID,@标志=标志 from #t where id=@i
   insert #t1 exec('dbcc inputbuffer('+@spid+')')
   if @标志='死锁的进程' exec('kill '+@spid)
   set @i=@i+1
  end
 end
 else
  while @i<=@count
  begin
   select @s='dbcc inputbuffer('+cast(进程ID as varchar)+')' from #t where id=@i
   insert #t1 exec(@s)
   set @i=@i+1
  end
 select a.*,进程的SQL语句=b.EventInfo
 from #t a join #t1 b on a.id=b.id
end

GO
SET QUOTED_IDENTIFIER OFF 
GO
SET ANSI_NULLS ON 
GO
View Code

 

----索引执行情况
SELECT objects.name ,
databases.name ,
indexes.name ,
user_seeks ,
user_scans ,
user_lookups ,
partition_stats.row_count
FROM sys.dm_db_index_usage_stats stats
LEFT JOIN sys.objects objects ON stats.object_id = objects.object_id
LEFT JOIN sys.databases databases ON databases.database_id = stats.database_id
LEFT JOIN sys.indexes indexes ON indexes.index_id = stats.index_id
AND stats.object_id = indexes.object_id
LEFT JOIN sys.dm_db_partition_stats partition_stats ON stats.object_id = partition_stats.object_id
AND indexes.index_id = partition_stats.index_id
WHERE 1 = 1
--AND databases.database_id = 7
AND objects.name IS NOT NULL
AND indexes.name IS NOT NULL
AND user_scans>0
ORDER BY user_scans DESC ,stats.object_id ,indexes.index_id
View Code

----最占用CPU
SELECT TOP 100 execution_count,
total_logical_reads /execution_count AS [Avg Logical Reads],
total_elapsed_time /execution_count AS [Avg Elapsed Time],
db_name(st.dbid) as [database name],
object_name(st.dbid) as [object name],
object_name(st.objectid) as [object name 1],
SUBSTRING(st.text, (qs.statement_start_offset / 2) + 1, 
((CASE statement_end_offset WHEN - 1 THEN DATALENGTH(st.text) ELSE qs.statement_end_offset END - qs.statement_start_offset) 
/ 2) + 1) AS statement_text
FROM sys.dm_exec_query_stats AS qs CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) AS st
WHERE execution_count > 100 AND qs.creation_time > dateadd(day,-3,getdate())
ORDER BY 1 DESC;
View Code


---执行时间最长的命令

SELECT TOP 10 COALESCE(DB_NAME(st.dbid),
DB_NAME(CAST(pa.value as int))+'*','Resource') AS DBNAME,
SUBSTRING(text,
-- starting value for substring
CASE WHEN statement_start_offset = 0
OR statement_start_offset IS NULL
THEN 1
ELSE statement_start_offset/2 + 1 END,
-- ending value for substring
CASE WHEN statement_end_offset = 0
OR statement_end_offset = -1
OR statement_end_offset IS NULL
THEN LEN(text)
ELSE statement_end_offset/2 END -
CASE WHEN statement_start_offset = 0
OR statement_start_offset IS NULL
THEN 1
ELSE statement_start_offset/2 END + 1
) AS TSQL,
total_logical_reads/execution_count AS AVG_LOGICAL_READS
FROM sys.dm_exec_query_stats
CROSS APPLY sys.dm_exec_sql_text(sql_handle) st
OUTER APPLY sys.dm_exec_plan_attributes(plan_handle) pa
WHERE attribute = 'dbid'
ORDER BY AVG_LOGICAL_READS DESC ;
View Code

----缺索引

SELECT TOP 30
[Total Cost] = ROUND(avg_total_user_cost * avg_user_impact * (user_seeks + user_scans),0)
, avg_user_impact, TableName = statement, [EqualityUsage] = equality_columns
, [InequalityUsage] = inequality_columns, [Include Cloumns] = 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;
View Code

 

--经常更新却很少使用的索引
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
WHERE DatabaseName = 'agilepoint50' ORDER BY [user_updates] DESC 
DROP TABLE #TempUnusedIndexes
View Code

 

---维护代价最高的索引
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 WHERE DatabaseName ='agilepoint50' ORDER BY [Maintenance cost] DESC 
DROP TABLE #TempMaintenanceCost
View Code

 

---表及数据库的空间占用
set nocount on
declare @db varchar(20)
set @db = db_name()
dbcc updateusage(@db) with no_infomsgs
go

create table #tblspace
(

数据表名称 varchar(50) null,
记录笔数 int null,
保留空间 varchar(15) null,
数据使用空间 varchar(15) null,
索引使用空间 varchar(15) null,
未使用空间 varchar(15) null,

)
declare @tblname varchar(50)
declare curtbls cursor for
select table_name from information_schema.tables
where table_type = 'base table'
open curtbls
Fetch next from curtbls into @tblname
while @@fetch_status = 0
begin
insert #tblspace exec sp_spaceused @tblname
fetch next from curtbls into @tblname
end
close curtbls
deallocate curtbls

select * from #tblspace order by
convert(int,left(保留空间,len(保留空间)-2)) desc
drop table #tblspace
View Code

 


 --检测死锁

--如果发生死锁了,我们怎么去检测具体发生死锁的是哪条SQL语句或存储过程?


--这时我们可以使用以下存储过程来检测,就可以查出引起死锁的进程和SQL语句。SQL Server自带的系统存储过程sp_who和sp_lock也可以用来查找阻塞和死锁, 但没有这里介绍的方法好用。

use master

go

create procedure sp_who_lock

as

begin

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 RETURN @@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 RETURN @@ERROR 

  

-- 找到临时表的记录数
 select  @intCountProperties = Count(*),@intCounter = 1

 from #tmp_lock_who

 

 IF @@ERROR<>0 RETURN @@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



drop table #tmp_lock_who



return 0

end
View Code

--杀死锁和进程

--如何去手动的杀死进程和锁?最简单的办法,重新启动服务。但是这里要介绍一个存储过程,通过显式的调用,可以杀死进程和锁。

use master

go



if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[p_killspid]') and OBJECTPROPERTY(id, N'IsProcedure') = 1)

drop procedure [dbo].[p_killspid]

GO



create proc p_killspid

@dbname varchar(200)    --要关闭进程的数据库名
as  

    declare @sql  nvarchar(500)  

    declare @spid nvarchar(20)



    declare #tb cursor for

        select spid=cast(spid as varchar(20)) from master..sysprocesses where dbid=db_id(@dbname)

    open #tb

    fetch next from #tb into @spid

    while @@fetch_status=0

    begin  

        exec('kill '+@spid)

        fetch next from #tb into @spid

    end  

    close #tb

    deallocate #tb

go
View Code

 



--用法
exec p_killspid 'newdbpy'

--查看锁信息

--如何查看系统中所有锁的详细信息?在企业管理管理器中,我们可以看到一些进程和锁的信息,这里介绍另外一种方法。

create table #t(req_spid int,obj_name sysname)



declare @s nvarchar(4000)

    ,@rid int,@dbname sysname,@id int,@objname sysname



declare tb cursor for 

    select distinct req_spid,dbname=db_name(rsc_dbid),rsc_objid

    from master..syslockinfo where rsc_type in(4,5)

open tb

fetch next from tb into @rid,@dbname,@id

while @@fetch_status=0

begin

    set @s='select @objname=name from ['+@dbname+']..sysobjects where id=@id'

    exec sp_executesql @s,N'@objname sysname out,@id int',@objname out,@id

    insert into #t values(@rid,@objname)

    fetch next from tb into @rid,@dbname,@id

end

close tb

deallocate tb



select 进程id=a.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

    ,对象id=rsc_objid

    ,对象名=b.obj_name

    ,rsc_indid

 from master..syslockinfo a left join #t b on a.req_spid=b.req_spid



go

drop table #t
View Code

 

 重置所有索引
USE xxxx; 
DECLARE @name varchar(100)

DECLARE authors_cursor CURSOR FOR  Select [name]   from sysobjects where xtype='u' order by id

OPEN authors_cursor

FETCH NEXT FROM authors_cursor  INTO @name

WHILE @@FETCH_STATUS = 0 
BEGIN    

 DBCC DBREINDEX (@name, '', 90)

 FETCH NEXT FROM authors_cursor     INTO @name 
END

deallocate authors_cursor

 

 
posted @ 2015-06-10 10:55  邑尘  阅读(253)  评论(0编辑  收藏  举报