经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 数据库/运维 » MS SQL Server » 查看文章
SQL Server一个特殊的阻塞案例分析2
来源:cnblogs  作者:潇湘隐者  时间:2019/5/13 8:54:26  对本文有异议

最近发现一个非常奇怪的阻塞问题,如下截图所示(来自监控工具DPA),会话583被会话1036阻塞,而且阻塞发生在tempdb,被阻塞的SQL如下截图所示,会话等待类型为LCK_M_S

 

 

clip_image001

 

 

 

 

clip_image002

 

因为DPA工具不好截取全部信息,使用下面SQL语句获取了阻塞会话的详细信息如下,来自Microsoft SQL Server Management Studio - Transact-SQL IntelliSense的的SQL被阻塞了

 

  1. SELECT  s.session_id ,
  1.         r.status ,
  1.         r.blocking_session_id 'Blk by' ,
  1.         r.wait_type ,
  1.         wait_resource ,
  1.         r.wait_time / ( 1000 * 60 ) 'Wait M' ,
  1.         r.cpu_time ,
  1.         r.logical_reads ,
  1.         r.reads ,
  1.         r.writes ,
  1.         r.total_elapsed_time / ( 1000 * 60 ) 'Elaps M' ,
  1.         SUBSTRING(st.text, ( r.statement_start_offset / 2 ) + 1,
  1.                   ( ( CASE r.statement_end_offset
  1.                         WHEN -1 THEN DATALENGTH(st.text)
  1.                         ELSE r.statement_end_offset
  1.                       END - r.statement_start_offset ) / 2 ) + 1) AS statement_text ,
  1.         COALESCE(QUOTENAME(DB_NAME(st.dbid)) + N'.'
  1.                  + QUOTENAME(OBJECT_SCHEMA_NAME(st.objectid, st.dbid)) + N'.'
  1.                  + QUOTENAME(OBJECT_NAME(st.objectid, st.dbid)), '') AS command_text ,
  1.         r.command ,
  1.         s.login_name ,
  1.         s.host_name ,
  1.         s.program_name ,
  1.         s.last_request_end_time ,
  1.         s.login_time ,
  1.         r.open_transaction_count
  1. FROM    sys.dm_exec_sessions AS s
  1.         JOIN sys.dm_exec_requests AS r ON r.session_id = s.session_id
  1.         CROSS APPLY sys.dm_exec_sql_text(r.sql_handle) AS st
  1. WHERE r.session_id =583
  1. ORDER BY r.cpu_time DESC;

 

clip_image001[4]

 

 

而会话1036处于睡眠(sleeping)状态,有一个Open的事务。通过wait_resource的值KEY: 2:1125899909070848 (79c68d10aa42)我们定位到是一个系统表sysschobj.它是sys.triggers这个系统视图的基表。如下所示:

 

 

clip_image004

 

 

 

clip_image005

 

 

  1. SET QUOTED_IDENTIFIER ON
  1. SET ANSI_NULLS ON
  1. GO
  1. CREATE VIEW sys.triggers AS
  1.     SELECT o.name,
  1.         object_id = o.id,
  1.         parent_class = o.pclass,
  1.         parent_class_desc = pc.name,
  1.         parent_id = o.pid,
  1.         type = o.type,
  1.         type_desc = n.name,
  1.         create_date = o.created,
  1.         modify_date = o.modified,
  1.         is_ms_shipped = sysconv(bit, o.status & 1),         -- OBJALL_MSSHIPPED
  1.         is_disabled = sysconv(bit, o.status & 256),         -- OBJTRG_DISABLED
  1.         is_not_for_replication = sysconv(bit, o.status & 512), -- OBJTRG_NOTFORREPL
  1.         is_instead_of_trigger = sysconv(bit, o.status & 1024)     -- OBJTRG_INSTEADOF
  1.     FROM sys.sysschobjs o
  1.     LEFT JOIN sys.syspalnames n ON n.class = 'OBTY' AND n.value = o.type
  1.     LEFT JOIN sys.syspalvalues pc ON pc.class = 'UNCL' AND pc.value = o.pclass
  1.     WHERE o.type IN ('TA','TR') AND o.pclass <> 100
  1.         AND has_access('TR', o.id, o.pid, o.nsclass) = 1
  1.  
  1. GO

 

 

 

使用下面脚本可以查到对应的锁信息(其实,正确的做法应该是加上条件过滤spid),从而可以判断,会话1036可能因为事务中,间接涉及对基表sysschobj的DML操作(有可能是衍生的系统视图),而由于事务没有提交也没有释放,导致在基表上的锁没有释放,从而导致出现这样一个阻塞。个人也很好奇是什么样的SQL会导致这样一个阻塞出现,不过这种阻塞源头是Sleeping状态的会话,已经无法定位阻塞源头SQL,只能通过Profile去跟踪捕获。但是这种阻塞出现时机和场景不清楚,很难一下子捕获到。

 

  1.  
  1. USE tempdb
  1. GO
  1. SELECT  request_session_id AS spid ,
  1.         DB_NAME(resource_database_id) AS dbname ,
  1.         CASE WHEN resource_type = 'OBJECT'
  1.              THEN OBJECT_NAME(resource_associated_entity_id)
  1.              WHEN resource_associated_entity_id = 0 THEN 'n/a'
  1.              ELSE OBJECT_NAME(p.object_id)
  1.         END AS entity_name ,
  1.         index_id ,
  1.         resource_type AS resource ,
  1.         resource_description AS description ,
  1.         request_mode AS mode ,
  1.         request_status AS status
  1. FROM    sys.dm_tran_locks t
  1. LEFT JOIN sys.partitions p
  1. ON      p.partition_id = t.resource_associated_entity_id
  1. WHERE   resource_database_id = DB_ID()

 

 

clip_image006

 

 

今天早上有发现同样的阻塞,猜测是SQL里面有创建临时表或对临时表做DDL或DML操作的迹象。不过依然没有找到源头SQL,只能静候下次机会。找出罪魁祸首。不过让我头痛的是,对于这种特殊阻塞情况,即使是使用Profile跟踪也是相当麻烦,因为不知道它什么时间点出现、出现在那个会话。

 

  1. SELECT  tl.resource_type AS [Resource Type] ,
  1.         DB_NAME(tl.resource_database_id) AS [DB Name] ,
  1.         CASE tl.resource_type
  1.           WHEN 'OBJECT'
  1.           THEN OBJECT_NAME(tl.resource_associated_entity_id,
  1.                            tl.resource_database_id)
  1.           WHEN 'DATABASE' THEN 'DB'
  1.           ELSE CASE WHEN tl.resource_database_id = DB_ID()
  1.                     THEN ( SELECT   OBJECT_NAME(object_id,
  1.                                                 tl.resource_database_id)
  1.                            FROM     sys.partitions
  1.                            WHERE    hobt_id = tl.resource_associated_entity_id
  1.                          )
  1.                     ELSE '(Run under DB context)'
  1.                END
  1.         END AS [Object] ,
  1.         tl.resource_description AS [Resource] ,
  1.         tl.request_session_id AS [Session] ,
  1.         tl.request_mode AS [Mode] ,
  1.         tl.request_status AS [Status] ,
  1.         wt.wait_duration_ms AS [Wait (ms)] ,
  1.         qi.sql ,
  1.         qi.query_plan
  1. FROM    sys.dm_tran_locks tl WITH ( NOLOCK )
  1. LEFT OUTER JOIN sys.dm_os_waiting_tasks wt WITH ( NOLOCK )
  1. ON      tl.lock_owner_address = wt.resource_address
  1.         AND tl.request_status = 'WAIT'
  1. OUTER APPLY ( SELECT    SUBSTRING(s.text,
  1.                                   ( er.statement_start_offset / 2 ) + 1,
  1.                                   ( ( CASE er.statement_end_offset
  1.                                         WHEN -1 THEN DATALENGTH(s.text)
  1.                                         ELSE er.statement_end_offset
  1.                                       END - er.statement_start_offset ) / 2 )
  1.                                   + 1) AS sql ,
  1.                         qp.query_plan
  1.               FROM      sys.dm_exec_requests er WITH ( NOLOCK )
  1.               CROSS APPLY sys.dm_exec_sql_text(er.sql_handle) s
  1.               OUTER APPLY sys.dm_exec_query_plan(er.plan_handle) qp
  1.               WHERE     tl.request_session_id = er.session_id
  1.             ) qi
  1. WHERE   tl.request_session_id =134

 

 

clip_image007

 

链接资料

一个特殊的SQL Server阻塞案例分析

SQL Server一个特殊的阻塞案例分析2

原文链接:http://www.cnblogs.com/kerrycode/p/10843279.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号