`
wsql
  • 浏览: 11789898 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
文章分类
社区版块
存档分类
最新评论

如何有效抓取SQL Server的BLOCKING信息

 
阅读更多
转自:微软亚太区数据库技术支持组 官方博客

SQL Server允许并发操作,BLOCKING是指在某一操作没有完成之前,其他操作必须等待,以便于保证数据的完整性。BLOCKING的解决方法要查看BLOCKING的头是什么,为什么BLOCKING头上的语句执行的很慢。通常来讲只要我们能找到BLOCKING头上的语句,我们总能够想出各种各种的办法,来提升性能,缓解或解决BLOCKING的问题。

但是问题的关键是,我们不知道BLOCKING什么时候会发生。用户跟我们抱怨数据库性能很差,等我们连上数据库去查看的时候,那时候有可能BLOCKING可能就已经过去了。性能又变好了。或者由于问题的紧急性,我们直接重新启动服务器以恢复运营。但是问题并没有最终解决,我们不知道下次问题会在什么时候发生。

BLOCKING问题的后果比较严重。因为终端用户能直接体验到。他们提交一个订单的时候,无论如何提交不上去,通常几秒之内能完成的一个订单提交,甚至要等待十几分钟,才能提交完成。更有甚者,极严重的BLOCKING能导致SQL Server停止工作。如下面的SQL ERRORLOG所表示,在短短的几分钟之内,SPID数据从158增长到694,并马上导致SQL Server打了一个dump,停止工作。我们很容易推断出问题的原因是由于BLOCKING导致的,但是我们无法得知BLOCKING HEADER是什么,我们必须要等下次问题重现时,辅之以工具,才能得知BLOCKING HEADER在做什么事情。如果信息抓取时机不对,我们可能要等问题发生好几次,才能抓到。这时候,客户和经理就会有抱怨了。因为我们的系统是生产系统,问题每发生一次,都会对客户带来损失。

2011-06-01 16:22:30.98 spid1931 Alert There are 158 Active database sessions which is too high.

2011-06-01 16:23:31.16 spid3248 Alert There are 342 Active database sessions which is too high.

2011-06-01 16:24:31.06 spid3884 Alert There are 517 Active database sessions which is too high.

2011-06-01 16:25:31.08 spid3688 Alert There are 694 Active database sessions which is too high.

2011-06-01 16:26:50.93 Server Using 'dbghelp.dll' version '4.0.5'

2011-06-01 16:26:50.97 Server **Dump thread -spid= 0, EC = 0x0000000000000000

2011-06-01 16:26:50.97 Server ***Stack Dump being sent to D:\MSSQL10.INSTANCE\MSSQL\LOG\SQLDump0004.txt

2011-06-01 16:26:50.97 Server * *******************************************************************************

2011-06-01 16:26:50.97 Server *

2011-06-01 16:26:50.97Server * BEGIN STACK DUMP:

2011-06-01 16:26:50.97 Server * 06/01/11 16:26:50spid4124

2011-06-01 16:26:50.97 Server *

2011-06-01 16:26:50.97 Server * Deadlocked Schedulers

2011-06-01 16:26:50.97 Server *

2011-06-01 16:26:50.97 Server * *******************************************************************************

2011-06-01 16:26:50.97 Server * -------------------------------------------------------------------------------

2011-06-01 16:26:50.97 Server * Short Stack Dump

2011-06-01 16:26:51.01 Server Stack Signature for the dump is 0x0000000000000258

BLOCKING的信息抓取有很多种方法。这里罗列了几种。并且对每种分析它的优缺点。以便我们选择。在枚举方法之前,我们先简单演示一下BLOCKING.

我们首先创建一个测试表:

DROPTABLE[TESTTABLE]

GO

CREATETABLE[dbo].[TESTTABLE](

[ID] [int]NULL,

[NAME] [nvarchar](50)NULL

)

GO

INSERTINTOTESTTABLEVALUES(1,'aaaa')

GO

然后打开一个查询窗口,执行下面的语句,该语句修改一行数据,并等待3分钟,然后在结束transaction

BEGINTRANSACTION

UPDATETESTTABLESET[NAME]='bbbb'WHERE[ID]=1

WAITFORDELAY'00:03:00'

COMMITTRANSACTION

这时候,如果打开另外一个查询窗口,执行下面的语句,下面的语句就会被BLOCK住。

UPDATETESTTABLESET[NAME]='cccc'WHERE[ID]=1

方法一,抓取SQL Profiler

======================

SQL Profiler里面包含大量的信息。其中有一个事件在Errors and Warnings->Blocked Process Report专门用来获得blocking的情况。但是因为信息量比较大,而且我们并不能很好的估算在什么时候会产生blocking,另外在生产环境使用Profiler,对性能可能会有影响,所以SQL Profiler并不是最合适的工具。我们在这里并不对它赘述。

方法二,执行查询

================

如果我们检查问题的时候,blocking还存在,那么,我们可以直接可以运行几个查询,得知BLOCKING HEADER的信息

SELECT*FROMsys.sysprocesseswherespid>50

上述查询只是告诉我们,BLOCKING HEADER的头是SPID=53,但是并没有告诉我们SPID=53在做什么事情。我们可以用下面的查询,得到SPID=53的信息

DBCCINPUTBUFFER(53)

我们可以把上述的两个查询合并起来,用下面的查询:

SELECTSPID=p.spid,

DBName=convert(CHAR(20),d.name),

ProgramName=program_name,

LoginName=convert(CHAR(20),l.name),

HostName=convert(CHAR(20),hostname),

Status=p.status,

BlockedBy=p.blocked,

LoginTime=login_time,

QUERY=CAST(TEXTASVARCHAR(MAX))

FROMMASTER.dbo.sysprocessesp

INNERJOINMASTER.dbo.sysdatabasesd

ONp.dbid=d.dbid

INNERJOINMASTER.dbo.sysloginsl

ONp.sid=l.sid

CROSSAPPLYsys.dm_exec_sql_text(sql_handle)

WHEREp.blocked=0

ANDEXISTS(SELECT1

FROMMASTER..sysprocessesp1

WHEREp1.blocked=p.spid)

这样,一次执行,就能告诉我们BLOCKING header的SPID信息,以及该SPID在做的语句。我们可以进一步研究该语句,以理解为什么该语句执行很慢。

用这个方法有一个缺点,就是使用的时候,要求BLOCKING是存在的。如果BLOCKING已经消失了,那么我们的方法就不管用了。

方法三,长期执行一个BLOCKING SCRIPT

==================================

因为我们通常无法知道BLOCKING什么时候会产生,所以通常的办法是我们长期运行一个BLOCKING SCRIPT,这样,等下次发生的时候,我们就会有足够的信息。长期运行BLOCKING SCRIPT对性能基本上是没有影响的。因为我们每隔10秒钟抓取一次信息。缺点是,如果问题一个月才发生一次,那么,我们的BLOCKING日志信息会很大。所以这种方法适用于几天之内能重现问题。

运行方法如下:

如果要停止运行,我们按ctrl+c就可以了。

BLOCKING的信息存在log.out这个文件中

我们可以打开log.out这个文件,会发现SPID 54被SPID 53给Block住了。

而随后,我们可以看到SPID=53在做什么事情:

下面是BLOCKING SCRIPT的脚本,我们可以把它存为blocking.sql

usemaster

go

while1=1

begin

print'Start time: '+convert(varchar(26),getdate(),121)

Print'Running processes'

selectspid,blocked,waittype,waittime,lastwaittype,waitresource,dbid,uid,cpu,physical_io,memusage,login_time,last_batch,

open_tran,status,hostname,program_name,cmd,net_library,loginame

fromsysprocesses

--where (kpid <> 0 ) or (spid < 51)

-- Change it if you only want to see the working processes

print'*********lockinfor***********'

selectconvert(smallint,req_spid)Asspid,

rsc_dbidAsdbid,

rsc_objidAsObjId,

rsc_indidAsIndId,

substring(v.name,1,4)AsType,

substring(rsc_text,1,16)asResource,

substring(u.name,1,8)AsMode,

substring(x.name,1,5)AsStatus

frommaster.dbo.syslockinfo,

master.dbo.spt_values v,

master.dbo.spt_values x,

master.dbo.spt_values u

wheremaster.dbo.syslockinfo.rsc_type=v.number

andv.type='LR'

andmaster.dbo.syslockinfo.req_status=x.number

andx.type='LS'

andmaster.dbo.syslockinfo.req_mode+1=u.number

andu.type='L'

orderbyspid

print'inputbuffer for running processes'

declare@spidvarchar(6)

declareibuffercursorfast_forwardfor

selectcast(spidasvarchar(6))asspidfromsysprocesseswherespid>50

openibuffer

fetchnextfromibufferinto@spid

while(@@fetch_status!=-1)

begin

print''

print'DBCC INPUTBUFFER FOR SPID '+@spid

exec('dbcc inputbuffer ('+@spid+')')

fetchnextfromibufferinto@spid

end

deallocateibuffer

waitfordelay'0:0:10'

End

这种方法的缺陷就是,log.out会比较巨大,会占用很大的空间,如果blocking一个月甚至更长时间才发生一次,那我们的这个方法就不太适宜。

方法四,我们用Agent Job来检查BLOCKING

=====================================

长期运行一个BLOCKING SCRIPT的缺点是我们每隔一段时间,去查询信息,但是大多数收集的信息是无用的。所以会导致日志文件巨大,对于一个生产系统来讲,磁盘空间满可不是个好事情,另外,有一些客户对于用命令行来长期运行TSQL脚本有所顾忌,所以我们做了一个改进。这次,我们只收集有用的信息。对于无用的信息我们不关注。这样能极大减少日志大小。

我们首先创建一个观察数据库,然后建立两张表格Blocking_sysprocesses和Blocking_SQLText,建立一个存储过程和一个Job,该Job每隔一段时间去调用存储过程。只有发现有blocking的,我们才记录到表格Blocking_sysprocesses和Blocking_SQLText这两个表格中。如果跟blocking无关,我们就不对它进行记录。下面是TSQL语句:

CREATEDATABASE[MonitorBlocking]

GO

USE[MonitorBlocking]

GO

CREATETABLEBlocking_sysprocesses(

[spid]smallint,

[kpid]smallint,

[blocked]smallint,

[waitType]binary(2),

[waitTime]bigInt,

[lastWaitType]nchar(32),

[waitResource]nchar(256),

[dbID]smallint,

[uid]smallint,

[cpu]int,

[physical_IO]int,

[memusage]int,

[login_Time]datetime,

[last_Batch]datetime,

[open_Tran]smallint,

[status]nchar(30),

[sid]binary(86),

[hostName]nchar(128),

[program_Name]nchar(128),

[hostProcess]nchar(10),

[cmd]nchar(16),

[nt_Domain]nchar(128),

[nt_UserName]nchar(128),

[net_Library]nchar(12),

[loginName]nchar(128),

[context_Info]binary(128),

[sqlHandle]binary(20),

[CapturedTimeStamp]datetime

)

GO

CREATETABLE[dbo].[Blocking_SqlText](

[spid] [smallint],

[sql_text] [nvarchar](2000),

[Capture_Timestamp] [datetime]

)

GO

CREATEPROCEDURE[dbo].[checkBlocking]

AS

BEGIN

SETNOCOUNTON;

SETTRANSACTIONISOLATIONLEVELREADUNCOMMITTED

declare@Durationint-- in milliseconds, 1000 = 1 sec

declare@nowdatetime

declare@Processesint

select@Duration=100-- in milliseconds, 1000 = 1 sec

select@Processes=0

select@now=getdate()

CREATETABLE#Blocks_rg(

[spid]smallint,

[kpid]smallint,

[blocked]smallint,

[waitType]binary(2),

[waitTime]bigInt,

[lastWaitType]nchar(32),

[waitResource]nchar(256),

[dbID]smallint,

[uid]smallint,

[cpu]int,

[physical_IO]int,

[memusage]int,

[login_Time]datetime,

[last_Batch]datetime,

[open_Tran]smallint,

[status]nchar(30),

[sid]binary(86),

[hostName]nchar(128),

[program_Name]nchar(128),

[hostProcess]nchar(10),

[cmd]nchar(16),

[nt_Domain]nchar(128),

[nt_UserName]nchar(128),

[net_Library]nchar(12),

[loginName]nchar(128),

[context_Info]binary(128),

[sqlHandle]binary(20),

[CapturedTimeStamp]datetime

)

INSERTINTO#Blocks_rg

SELECT

[spid],

[kpid],

[blocked],

[waitType],

[waitTime],

[lastWaitType],

[waitResource],

[dbID],

[uid],

[cpu],

[physical_IO],

[memusage],

[login_Time],

[last_Batch],

[open_Tran],

[status],

[sid],

[hostName],

[program_name],

[hostProcess],

[cmd],

[nt_Domain],

[nt_UserName],

[net_Library],

[loginame],

[context_Info],

[sql_Handle],

@nowas[Capture_Timestamp]

FROMmaster..sysprocesseswhereblocked<>0

ANDwaitTime>@Duration

SET@Processes=@@rowcount

INSERTinto#Blocks_rg

SELECT

src.[spid],

src.[kpid],

src.[blocked],

src.[waitType],

src.[waitTime],

src.[lastWaitType],

src.[waitResource],

src.[dbID],

src.[uid],

src.[cpu],

src.[physical_IO],

src.[memusage],

src.[login_Time],

src.[last_Batch],

src.[open_Tran],

src.[status],

src.[sid],

src.[hostName],

src.[program_name],

src.[hostProcess],

src.[cmd],

src.[nt_Domain],

src.[nt_UserName],

src.[net_Library],

src.[loginame],

src.[context_Info],

src.[sql_Handle]

,@nowas[Capture_Timestamp]

FROMmaster..sysprocessessrcinnerjoin#Blocks_rg trgt

ontrgt.blocked=src.[spid]

if@Processes>0

BEGIN

INSERT[dbo].[Blocking_sysprocesses]

SELECT*from#Blocks_rg

DECLARE@SQL_Handlebinary(20),@SPIDsmallInt;

DECLAREcur_handleCURSORFORSELECTsqlHandle,spidFROM#Blocks_rg;

OPENcur_Handle

FETCHNEXTFROMcur_handleINTO@SQL_Handle,@SPID

WHILE(@@FETCH_STATUS=0)

BEGIN

INSERT[dbo].[Blocking_SqlText]

SELECT@SPID,CONVERT(nvarchar(4000),[text]),@nowas[Capture_Timestamp]from::fn_get_sql(@SQL_Handle)

FETCHNEXTFROMcur_handleINTO@SQL_Handle,@SPID

END

CLOSEcur_Handle

DEALLOCATEcur_Handle

END

DROPtable#Blocks_rg

END

GO

USEmsdb;

GO

EXECdbo.sp_add_job

@job_name=N'MonitorBlocking';

GO

EXECsp_add_jobstep

@job_name=N'MonitorBlocking',

@step_name=N'execute blocking script',

@subsystem=N'TSQL',

@command=N'exec checkBlocking',

@database_name=N'MonitorBlocking';

GO

EXECsp_add_jobSchedule

@name=N'ScheduleBlockingCheck',

@job_name=N'MonitorBlocking',

@freq_type=4,-- daily

@freq_interval=1,

@freq_subday_type=4,

@freq_subday_interval=1

EXECsp_add_jobserver@job_name=N'MonitorBlocking',@server_name=N'(local)'

当Blocking发生一段时间后,我们可以查询下面的两个表格,以得知当时问题发生时的blocking信息:

useMonitorBlocking

GO

SELECT*fromBlocking_sqlText

SELECT*FROMBlocking_sysprocesses

分享到:
评论

相关推荐

    SQL Server Blocking and Deadlock

    SQL SERVER 的阻塞和死锁,讲解的比较详细,可以参考看看

    Beginning SQL Server 2005 Administration

    unique tips and tricks, and useful workarounds, the authors help you handle even the most difficult SQL Server 2005 administration issues, including blocking and locking. You’ll learn how to fine-...

    Pro.SQL.Server.Internals

    Improve your ability to develop, manage, and troubleshoot SQL Server solutions by learning how different components work “under the hood,” and how they communicate with each other. The detailed ...

    SQL Server并发性:锁定,阻止和行版本控制SQL Server Concurrency: Locking, Blocking and Row Versioning

    一本面向想要了解SQL Server并发性以及如何解决过多的阻塞或死锁问题的DBA和开发人员的书。

    Inside Microsoft SQL Server 2000

    1. The Evolution of Microsoft SQL Server: 1989 to 2000 [加入我的離線書架] . SQL Server: The Early Years . Ron's Story . Kalen's Story . Microsoft SQL Server Ships . Development Roles Evolve . OS...

    完全剖析Microsoft SQL Server 7.0

    1. 微軟SQL Server的發展歷史:1989到1999 [加入我的離線書架] . Ron的故事 . Kalen的故事 . Microsoft SQL Server發行 . 發展過程中的角色 . OS/2和合作伙伴間的戰火(Friendly Fire) . 4.2版 . SQL Server...

    Professional Microsoft SQL Server 2008 Administration

    Chapter 13 describes how to monitor your SQL Server instance for problematic issues such as blocking and locking. Chapters 14 and 15 discuss how to optimize the T-SQL that accesses your tables and ...

    Expert SQL Server Transactions and Locking

    Master SQL Server’s Concurrency Model so you can implement high-throughput systems that deliver transactional consistency to your application customers. This book explains how to troubleshoot and ...

    SQL Server常见问题及解决方法分享

    主要为大家详细介绍了SQL Server常见问题及解决方法,包括SQL Server连接问题,SQL Server日志问题,SQL Server查询很久等问题,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

    Microsoft SQL Server 2012 T-SQL Fundamentals

    Get started with the ... update, delete, and merge data Go beyond the fundamentals with pivoting techniques and set grouping Isolate inconsistent data and address deadlock and blocking scenarios

    在SQL Server里为什么我们需要更新锁

    我想讲解一个特别的问题,在我每次讲解SQL Server里的锁和阻塞(Locking & Blocking)都会碰到的问题:在SQL Server里,为什么我们需要更新锁?在我们讲解具体需要的原因前,首先我想给你介绍下当更新锁(Update(U...

    为什么我们需要在SQL Server里更新锁

    每次讲解SQL Server里的锁和阻塞(Locking & Blocking)都会碰到的问题:在SQL Server里,为什么我们需要更新锁?在我们讲解具体需要的原因前,首先我想给你介绍下当更新锁(Update(U)Lock)获得时,根据它的兼容...

    Troubleshooting SQL Server - A Guide for the Accidental DBA

    其次再说,这是一份非常好的资料,关于SQL Server性能调优和故障排除的难得的一本好书。前提是你的有良好的英文阅读能力。 最后,目录如下: 1、A Performance Troubleshooting Methodology 2、Disk I/O ...

    DeadlockDetector 无限使用版

    Identify blocking SQL code, locked objects and deadlock victims with pinpoint accuracy Accelerate system response time by reducing long lock waits SQL Deadlock Detector is a Zero-impact SQL server ...

    SqlServer中如何解决session阻塞问题

    在Sql Server 中当一个数据库会话中的事务正锁定一个或多个其他会话事务想要读取或修改的资源时,会产生阻塞(Blocking)。通常短时间的阻塞没有问题,且是较忙的应用程序所需要的。然而,设计糟糕的应用程序会导致长...

    微软内部资料-SQL性能优化3

     Analyze the output of blocking scripts and Microsoft® SQL Server™ Profiler to troubleshoot locking and blocking issues.  Formulate hypothesis to resolve locking and blocking issues. ...

    sql最全的常用命令语句

    select blocking_session_id, session_id,db_name(database_id) as dbname,text from master.sys.dm_exec_requests a CROSS APPLY master.sys.dm_exec_sql_text(a.sql_handle) ), tb1 as ( select a.*,login_time,...

    SQL2008中SQL应用之-阻塞(Blocking)应用分析

    当一个数据库会话中的事务正锁定一个或多个其他会话事务想要读取或修改的资源时,会产生阻塞(Blocking)。

    oracle RAC查看blocking的脚本

    oracle RAC查看blocking的脚本

    non-blocking socket

    using select to implement socket multiplexing, and non-blocking, asynchronous IO

Global site tag (gtag.js) - Google Analytics