在SQLServer2005和SQLServer2000里怎样监视阻塞

在SQLServer2005和SQLServer2000里怎样监视阻塞

--王成辉翻译整理,转贴请注明出自微软BI开拓者www.windbi.com

--原帖地址


综述
本文讲述怎样设计和使用一个存储过程来诊断阻塞和性能问题。

SQLServer2005里,你可以在事件探查器里使用Blocked Process Report事件类来捕捉阻塞。关于该事件类的更多信息,请查看MSDN网站:http://msdn2.microsoft.com/en-us/library/ms191168.aspx

更多信息

下面描述了存储过程sp_blocker_pss80捕获的信息,该信息也适用于SQLServer2005

  • 开始时间(根据运行SQLServer的计算机确定),便于阻塞的取样能和其他性能信息的时间对照,如性能监视器或事件探查器日志

  • 关于连接到SQLServer的信息,通过查询系统表sysprocesses可以得到

  • 关于锁资源,通过查询系统表syslockinfo可以得到

  • 关于资源等待信息,通过运行DBCC SQLPERF(WAITSTATS)可以得到

  • 目前运行的被其他连接阻塞或阻塞其他连接的批语句,通过可以DBCC INPUTBUFFER得到

  • 结束时间,根据运行SQLServer的计算机确定


为了尽可能的减少运行该存储过程的影响,创建过程时按照下面的规则:


  • 除非至少有一个连接在等待资源,否则不输出任何结果。

  • 为了提升性能并禁止该过程被阻塞,系统表sysprocesses和syslockinfo直接从master数据库里查询。因此,该过程用于SQLServer2000及以上版本。

  • 为了获得DBCC INPUTBUFFER的输出结果,通过游标创建一个小表。这对tempdb数据库的使用没有明显的影响。

  • 由于收集信息时阻塞可能改变,fast mode的存在可以通过减少系统表sysprocesses和syslockinfo的相关行数来增加性能。

  • 如果试图跟踪non-lock资源等待,latch mode的存在可以忽略锁的输出结果。

从任何一个查询工具里运行该存储过程是有用的。然而,微软建议你按照下面的步骤进行阻塞分析:
  • 创建存储过程sp_blocker_pss80,本文结束有脚本,从任何一个查询工具用具有sysadmin权限登录到SQLServer服务器或你计划监控的实例。

  • 创建一个如下的脚本循环的运行存储过程。注意应该延迟5到60秒:
    WHILE 1=1
    BEGIN
      EXEC master.dbo.sp_blocker_pss80
      -- Or for fast mode
      -- EXEC master.dbo.sp_blocker_pss80 @fast=1
      -- Or for latch mode
      -- EXEC master.dbo.sp_blocker_pss80 @latch=1
      WAITFOR DELAY '00:00:15'
    END
    GO


  • 一并使用性能监视器日志和事件探查器日志时输出结果更有用,所以建议同时创建它们。关于事件探查器和性能监视器需要捕捉的信息和信息结果的解释,请点击这里查看微软知识库

  • 为了让监视用的查询工具避免网络不能连接连的问题,从Isql.exe、Osql.exe查询工具或者运行SQLServer的计算机的命令提示符工具Sqlcmd运行第二步创建的脚本文件。下面的例子是从命令行运行Osql.exe工具,假定客户端运行在SQLServer运行的计算机上,脚本文件名为Checkblk.sql。确保-S参数正确,将server替换为你SQLServer服务器的名称(或服务器名称\实例名,如果你监视的是一个命名实例的话)。-i 参数也要正确,将checkblk.sql替换为你第二步里创建的脚本文件的路径和文件名。
    osql -E -Sserver -icheckblk.sql -ocheckblk.out -w2000

注意由于下面的原因你必须使用其他命令行
  • 为了更易读,禁止在输出文件里换行

  • 为了将输出结果保持到文件而不是屏幕,使用-o参数,以便查询工具有问题的话,你仍然有到查询工具失败时的输出结果。

存储过程sp_blocker_pss80的脚本如下:

create procedure dbo.sp_blocker_pss80 (@latch int = 0, @fast int = 1, @appname sysname='PSSDIAG')
as
--version 17SP3
if is_member('sysadmin')=0
begin
  print 'Must be a member of the sysadmin group in order to run this procedure'
  return
end


set nocount on
SET LANGUAGE 'us_english'
declare @spid varchar(6)
declare @blocked varchar(6)
declare @time datetime
declare @time2 datetime
declare @dbname nvarchar(128)
declare @status sql_variant
declare @useraccess sql_variant


set @time = getdate()
declare @probclients table(spid smallint, ecid smallint, blocked smallint, waittype binary(2), dbid smallint,
  ignore_app tinyint, primary key (blocked, spid, ecid))
insert @probclients select spid, ecid, blocked, waittype, dbid,
  case when convert(varchar(128),hostname) = @appname then 1 else 0 end
  from master.dbo.sysprocesses where blocked!=0 or waittype != 0x0000


if exists (select spid from @probclients where ignore_app != 1 or waittype != 0x020B)
begin
  set @time2 = getdate()
  print ''
  print '8.2 Start time: ' + convert(varchar(26), @time, 121) + ' ' + convert(varchar(12), datediff(ms,@time,@time2))


  insert @probclients select distinct blocked, 0, 0, 0x0000, 0, 0 from @probclients
      where blocked not in (select spid from @probclients) and blocked != 0


  if (@fast = 1)
  begin
      print ''
      print 'SYSPROCESSES ' + ISNULL (@@servername,'(null)') + ' ' + str(@@microsoftversion)


      select spid, status, blocked, open_tran, waitresource, waittype,
        waittime, cmd, lastwaittype, cpu, physical_io,
        memusage, last_batch=convert(varchar(26), last_batch,121),
        login_time=convert(varchar(26), login_time,121),net_address,
        net_library, dbid, ecid, kpid, hostname, hostprocess,
        loginame, program_name, nt_domain, nt_username, uid, sid,
        sql_handle, stmt_start, stmt_end
      from master.dbo.sysprocesses
      where blocked!=0 or waittype != 0x0000
        or spid in (select blocked from @probclients where blocked != 0)
        or spid in (select spid from @probclients where blocked != 0)


      print 'ESP ' + convert(varchar(12), datediff(ms,@time2,getdate()))


      print ''
      print 'SYSPROC FIRST PASS'
      select spid, ecid, waittype from @probclients where waittype != 0x0000


      if exists(select blocked from @probclients where blocked != 0)
      begin
        print 'Blocking via locks at ' + convert(varchar(26), @time, 121)
        print ''
        print 'SPIDs at the head of blocking chains'
        select spid from @probclients
            where blocked = 0 and spid in (select blocked from @probclients where spid != 0)
        if @latch = 0
        begin
            print 'SYSLOCKINFO'
            select @time2 = getdate()


            select spid = convert (smallint, req_spid),
              ecid = convert (smallint, req_ecid),
              rsc_dbid As dbid,
              rsc_objid As ObjId,
              rsc_indid As IndId,
              Type = case rsc_type when 1 then 'NUL'
                                    when 2 then 'DB'
                                    when 3 then 'FIL'
                                    when 4 then 'IDX'
                                    when 5 then 'TAB'
                                    when 6 then 'PAG'
                                    when 7 then 'KEY'
                                    when 8 then 'EXT'
                                    when 9 then 'RID'
                                    when 10 then 'APP' end,
              Resource = substring (rsc_text, 1, 16),
              Mode = case req_mode + 1 when 1 then NULL
                                        when 2 then 'Sch-S'
                                        when 3 then 'Sch-M'
                                        when 4 then 'S'
                                        when 5 then 'U'
                                        when 6 then 'X'
                                        when 7 then 'IS'
                                        when 8 then 'IU'
                                        when 9 then 'IX'
                                        when 10 then 'SIU'
                                        when 11 then 'SIX'
                                        when 12 then 'UIX'
                                        when 13 then 'BU'
                                        when 14 then 'RangeS-S'
                                        when 15 then 'RangeS-U'
                                        when 16 then 'RangeIn-Null'
                                        when 17 then 'RangeIn-S'
                                        when 18 then 'RangeIn-U'
                                        when 19 then 'RangeIn-X'
                                        when 20 then 'RangeX-S'
                                        when 21 then 'RangeX-U'
                                        when 22 then 'RangeX-X'end,
              Status = case req_status when 1 then 'GRANT'
                                        when 2 then 'CNVT'
                                        when 3 then 'WAIT' end,
              req_transactionID As TransID, req_transactionUOW As TransUOW
            from master.dbo.syslockinfo s,
              @probclients p
            where p.spid = s.req_spid


            print 'ESL ' + convert(varchar(12), datediff(ms,@time2,getdate()))
        end -- latch not set
      end
      else
        print 'No blocking via locks at ' + convert(varchar(26), @time, 121)
      print ''
  end  -- fast set


  else 
  begin  -- Fast not set
      print ''
      print 'SYSPROCESSES ' + ISNULL (@@servername,'(null)') + ' ' + str(@@microsoftversion)


      select spid, status, blocked, open_tran, waitresource, waittype,
        waittime, cmd, lastwaittype, cpu, physical_io,
        memusage, last_batch=convert(varchar(26), last_batch,121),
        login_time=convert(varchar(26), login_time,121),net_address,
        net_library, dbid, ecid, kpid, hostname, hostprocess,
        loginame, program_name, nt_domain, nt_username, uid, sid,
        sql_handle, stmt_start, stmt_end
      from master.dbo.sysprocesses


      print 'ESP ' + convert(varchar(12), datediff(ms,@time2,getdate()))


      print ''
      print 'SYSPROC FIRST PASS'
      select spid, ecid, waittype from @probclients where waittype != 0x0000


      if exists(select blocked from @probclients where blocked != 0)
      begin
        print 'Blocking via locks at ' + convert(varchar(26), @time, 121)
        print ''
        print 'SPIDs at the head of blocking chains'
        select spid from @probclients
        where blocked = 0 and spid in (select blocked from @probclients where spid != 0)
        if @latch = 0
        begin
            print 'SYSLOCKINFO'
            select @time2 = getdate()


            select spid = convert (smallint, req_spid),
              ecid = convert (smallint, req_ecid),
              rsc_dbid As dbid,
              rsc_objid As ObjId,
              rsc_indid As IndId,
              Type = case rsc_type when 1 then 'NUL'
                                    when 2 then 'DB'
                                    when 3 then 'FIL'
                                    when 4 then 'IDX'
                                    when 5 then 'TAB'
                                    when 6 then 'PAG'
                                    when 7 then 'KEY'
                                    when 8 then 'EXT'
                                    when 9 then 'RID'
                                    when 10 then 'APP' end,
              Resource = substring (rsc_text, 1, 16),
              Mode = case req_mode + 1 when 1 then NULL
                                        when 2 then 'Sch-S'
                                        when 3 then 'Sch-M'
                                        when 4 then 'S'
                                        when 5 then 'U'
                                        when 6 then 'X'
                                        when 7 then 'IS'
                                        when 8 then 'IU'
                                        when 9 then 'IX'
                                        when 10 then 'SIU'
                                        when 11 then 'SIX'
                                        when 12 then 'UIX'
                                        when 13 then 'BU'
                                        when 14 then 'RangeS-S'
                                        when 15 then 'RangeS-U'
                                        when 16 then 'RangeIn-Null'
                                        when 17 then 'RangeIn-S'
                                        when 18 then 'RangeIn-U'
                                        when 19 then 'RangeIn-X'
                                        when 20 then 'RangeX-S'
                                        when 21 then 'RangeX-U'
                                        when 22 then 'RangeX-X'end,
              Status = case req_status when 1 then 'GRANT'
                                        when 2 then 'CNVT'
                                        when 3 then 'WAIT' end,
              req_transactionID As TransID, req_transactionUOW As TransUOW
            from master.dbo.syslockinfo


            print 'ESL ' + convert(varchar(12), datediff(ms,@time2,getdate()))
        end -- latch not set
      end
      else
        print 'No blocking via locks at ' + convert(varchar(26), @time, 121)
      print ''
  end -- Fast not set


  print 'DBCC SQLPERF(WAITSTATS)'
  dbcc sqlperf(waitstats)


  Print ''
  Print '*********************************************************************'
  Print 'Print out DBCC Input buffer for all blocked or blocking spids.'
  Print '*********************************************************************'


  declare ibuffer cursor fast_forward for
  select distinct cast (spid as varchar(6)) as spid
  from @probclients
  where (spid <> @@spid) and
      ((blocked!=0 or (waittype != 0x0000 and ignore_app = 0))
      or spid in (select blocked from @probclients where blocked != 0))
  open ibuffer
  fetch next from ibuffer into @spid
  while (@@fetch_status != -1)
  begin
      print ''
      print 'DBCC INPUTBUFFER FOR SPID ' + @spid
      exec ('dbcc inputbuffer (' + @spid + ')')


      fetch next from ibuffer into @spid
  end
  deallocate ibuffer


  Print ''
  Print '*******************************************************************************'
  Print 'Print out DBCC OPENTRAN for active databases for all blocked or blocking spids.'
  Print '*******************************************************************************'
  declare ibuffer cursor fast_forward for
  select distinct cast (dbid as varchar(6)) from @probclients
  where dbid != 0
  open ibuffer
  fetch next from ibuffer into @spid
  while (@@fetch_status != -1)
  begin
      print ''
      set @dbname = db_name(@spid)
      set @status = DATABASEPROPERTYEX(@dbname,'Status')
      set @useraccess = DATABASEPROPERTYEX(@dbname,'UserAccess')
      print 'DBCC OPENTRAN FOR DBID ' + @spid + ' ['+ @dbname + ']'
      if @status = N'ONLINE' and @useraccess != N'SINGLE_USER'
        dbcc opentran(@dbname)
      else
        print 'Skipped: Status=' + convert(nvarchar(128),@status)
            + ' UserAccess=' + convert(nvarchar(128),@useraccess)


      print ''
      if @spid = '2' select @blocked = 'Y'
      fetch next from ibuffer into @spid
  end
  deallocate ibuffer
  if @blocked != 'Y'
  begin
      print ''
      print 'DBCC OPENTRAN FOR DBID  2 [tempdb]'
      dbcc opentran ('tempdb')
  end


  print 'End time: ' + convert(varchar(26), getdate(), 121)
end -- All
else
  print '8 No Waittypes: ' + convert(varchar(26), @time, 121) + ' '
    + convert(varchar(12), datediff(ms,@time,getdate())) + ' ' + ISNULL (@@servername,'(null)')


GO


最后编辑拓狼 最后编辑于 2007-05-24 11:47:16
虽有智慧,不如乘势;虽有鎡基,不如待时。
君子学以聚之,问以辨之,宽以居之,仁以行之。
独学而无友,则孤陋而寡闻。