【问题标题】:Find all sql statements in a xaction which deadlocked from memory dump查找从内存转储死锁的 xaction 中的所有 sql 语句
【发布时间】:2011-10-05 15:34:16
【问题描述】:

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

我已经知道的

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

  2. 我知道我应该将内存转储发送给微软,然后获取然后分析它。但是我想知道我们是否有希望在没有私有符号的情况下解决这个问题。

问题:

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

我正在通过管理工作室手动创建这个死锁场景。 假设 1 个死锁的 xaction 中有 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对应的线程中查找历史。


为什么要转储内存:
因为如果我必须在生产中进行此设置,则影响最小。

【问题讨论】:

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


    【解决方案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 和偏移信息,然后您可以使用 sys.dm_exec_sql_text() 将 TSQL 堆栈中的语句取回。如果您尝试一次手动执行单个语句来触发死锁,您将无法执行此操作,因为每个堆栈只会包含您在其中执行的单个语句。

    来自附加信息的更新:

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

    【讨论】:

    • 我使用 .foreach (obj {s -[1]u 0 l?fffffff "update"}) {.printf "\n%mu",${obj}} 和我能够找到第二个 sql stmt 但不是第一个。感谢乔纳森的帮助。
    猜你喜欢
    • 1970-01-01
    • 2012-02-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-03
    相关资源
    最近更新 更多