查找从内存转储中死锁的xaction中的所有sql语句

时间:2011-10-05 15:34:17

标签: sql-server sql-server-2008 debugging windbg memory-dump

环境:
Sql server 2008 r2
Windows 7 64位
Windbg 64bit

我已经知道

  1. 我可以通过运行服务器端探查器跟踪并在发生死锁时立即停止来查找此事务中的sql stmts。然后在跟踪文件中搜索事务ID。但这是一种强力方法,不能总是在生产环境中完成。

  2. 我知道我应该将内存转储发送到微软,然后分析它。但我想找到我们的,如果没有私人符号就有希望解决这个问题。

  3. 问题:

    当2个事务死锁(lock_deadlock event)时,我在sql server中使用扩展事件创建内存转储。

    我通过管理工作室手动创建此死锁场景。 让我们说死锁的xaction中有1个包含2个sql语句。

    begin tran
      update tabl1 ... -- sql stmt 1
    go
      update tabl2 ..  -- sql stmt 2
    

    现在我在我的内存转储中找到了这个帖子,我只能找到我的sql stmt 2,即“更新tabl2”。

    无论如何,我可以查找线程在xaction中执行的所有sql stmts,即在我们的情况下“update tabl1 ..”?我想知道线程之前在同一个事务中执行了什么。由于在转储时尚未提交此xaction,因此值应位于线程内存中的某处。

    如果我在这里没有意义,请告诉我。我有一段时间以来一直在关注这个问题 我想知道这是否可能。

    附加信息

    背景:
    我们有性能测试环境,我们运行12小时负载测试。第二天早上,我们分析并找出僵局。应用程序在事务中执行7-8个dml语句(我们使用hibernate)。因为基于sys.dm_exec_sql_text只会在缓存中产生结果,所以我们不会得到整套dml语句,因为我们在第二天分析它(ps:我甚至没试过这个,当问题在1之后报告给我天)

    我们今天如何解决这个问题:
    1.设置服务器端跟踪
    2.设置事件通知,该事件通知在死锁时触发并调用sp来停止跟踪 3.从扩展事件xml报告或分析器中,我们找到事务ID并查找与之相对应的过去语句

    我怎么想我能解决这个问题:
    1.在包含系统ID的扩展事件“lock_deadlock”上触发内存转储 2.以某种方式尝试在与系统ID对应的线程中查找历史记录

    为什么内存转储:
    因为如果必须在生产中进行此设置将导致影响最小。

1 个答案:

答案 0 :(得分:1)

你已经过度工程了。我并不声称知道线程内存的所有复杂细节,但没有理由让它保持语句最后执行本地,它不需要它执行事务的回滚,这是使用日志完成的必要时来自事务日志的记录。找出死锁原因所需的一切都已包含在死锁图XML中。你绝对不需要内存转储来解决它。每个进程的TSQL执行堆栈都包含在进程下的元素中。例如:

  <process-list>
    <process id="process807b6bc8" taskpriority="0" logused="0" waitresource="KEY: 14:72057594038845440 (1a39e6095155)" waittime="4739" ownerId="163539" transactionname="INSERT EXEC" lasttranstarted="2011-10-05T12:29:22.580" XDES="0x82b318b0" lockMode="S" schedulerid="2" kpid="1764" status="suspended" spid="57" sbid="0" ecid="0" priority="0" trancount="1" lastbatchstarted="2011-10-05T12:29:04.563" lastbatchcompleted="2011-10-05T12:29:04.563" clientapp="Microsoft SQL Server Management Studio - Query" hostname="SQL2K8R2-IE2" hostpid="3736" loginname="SQLSKILLSDEMOS\administrator" isolationlevel="read committed (2)" xactid="163539" currentdb="14" lockTimeout="4294967295" clientoption1="673187936" clientoption2="390200">
      <executionStack>
        <frame procname="" line="3" stmtstart="118" stmtend="284" sqlhandle="0x03000e0020c96c7ef2b3cd00739f00000100000000000000" />
        <frame procname="" line="3" stmtstart="50" stmtend="146" sqlhandle="0x02000000e00b66366c680fabe2322acbad592a896dcab9cb" />
      </executionStack>
      <inputbuf>
WHILE (1=1) 
BEGIN
    INSERT INTO #t1 EXEC BookmarkLookupSelect 4
    TRUNCATE TABLE #t1
END
   </inputbuf>
    </process>
    <process id="process807b7288" taskpriority="0" logused="228" waitresource="KEY: 14:72057594038910976 (e5b3d7e750dd)" waittime="4742" ownerId="163545" transactionname="UPDATE" lasttranstarted="2011-10-05T12:29:22.587" XDES="0x82b6f950" lockMode="X" schedulerid="2" kpid="12" status="suspended" spid="58" sbid="0" ecid="0" priority="0" trancount="2" lastbatchstarted="2011-10-05T12:29:10.607" lastbatchcompleted="2011-10-05T12:29:10.600" clientapp="Microsoft SQL Server Management Studio - Query" hostname="SQL2K8R2-IE2" hostpid="3736" loginname="SQLSKILLSDEMOS\administrator" isolationlevel="read committed (2)" xactid="163545" currentdb="14" lockTimeout="4294967295" clientoption1="673187936" clientoption2="390200">
      <executionStack>
        <frame procname="" line="4" stmtstart="120" stmtend="262" sqlhandle="0x03000e0059ed607ff3b3cd00739f00000100000000000000" />
        <frame procname="" line="4" stmtstart="82" stmtend="138" sqlhandle="0x020000002a7093322fbd674049d04f1dc0f3257646c4514b" />
      </executionStack>
      <inputbuf>
SET NOCOUNT ON
WHILE (1=1) 
BEGIN
    EXEC BookmarkLookupUpdate 4
END
   </inputbuf>
    </process>
  </process-list>

您所要做的就是从帧中获取sqlhandle和offset信息,然后使用sys.dm_exec_sql_text()将TSQL堆栈中的语句取回。如果您尝试一次一个地手动执行单个语句来触发死锁,则无法执行此操作,因为每个堆栈只会包含您在其中执行的单个语句。

从附加信息更新:

使用内部队列激活的事件通知来收集附加信息是您完成所需操作的最佳方式,它比执行内存转储要便宜得多。激活存储过程为事件通知执行,以异步方式收集数据,其中内存转储在扩展事件中的触发线程上作为Action同步执行。