title: How to interpret a t-sql deadlock trace
body: <p>I'm trying to sort out a deadlock by looking at the t-sql trace but I'm struggling to understand the information. I have a summary of the info here and then the full deadlock trace at the end of the post:</p>
  
  <p>The first lock is on a table called dbo.RetailVoucher<br>
  The second lock is on a table called ooc.PlannedUniversalVoucher</p>
  
  <p>The 1st stored procedure reads the following tables:<br>
  dbo.RetailVoucher, ooc.PlannedOrderItem and ooc.PlannedOrder.</p>
  
  <p>The 2nd stored procedure reads the following tables:<br>
  ooc.PlannedBatch &amp; ooc.PlannedUniversalVoucher</p>
  
  <p>Now, for the procedures to be waiting for each other, I thought they would both have to be reading the same table at some point. I obviously don't understand how to interpret the trace. Do I need to hunt down the source of the locks on dbo.RetailerVoucher and ooc.PlannedUniversalVoucher in other procedures?</p>
  
  <p>Thanks.</p>
  
  <p>Here's the full trace:</p>
  
  <pre><code>&lt;deadlock-list&gt;
   &lt;deadlock victim="process894748"&gt;
    &lt;process-list&gt;
     &lt;process id="process894748" taskpriority="0" logused="3064" waitresource="KEY: 8:72057594084655104 (845afc30a382)" waittime="944" ownerId="12987790066" transactionname="user_transaction" lasttranstarted="2014-04-10T19:07:02.250" XDES="0x803d53c0" lockMode="S" schedulerid="3" kpid="14356" status="suspended" spid="67" sbid="0" ecid="0" priority="0" trancount="3" lastbatchstarted="2014-04-10T19:07:02.287" lastbatchcompleted="2014-04-10T19:07:02.287" clientapp=".Net SqlClient Data Provider" hostname="ID13115" hostpid="4872" loginname="UVUser" isolationlevel="read committed (2)" xactid="12987790066" currentdb="8" lockTimeout="4294967295" clientoption1="673185824" clientoption2="128056"&gt;
      &lt;executionStack&gt;
       &lt;frame procname="UVSystem.ooc.PlannedPacketPreserveEVouchers" line="144" stmtstart="12286" stmtend="13618" sqlhandle="0x0300080039a18c7fa2ed9800dda200000100000000000000"&gt;
  update dbo.RetailVoucher
              set QuantityInStock -= rvsum.QuantitySum
              from dbo.RetailVoucher urv
              join (
                  select oib.id, SUM(oib.Quantity) as QuantitySum
                  from (
                      select coalesce(rv.RelatedVoucherId, rv.Id) id, oi.Quantity
                      from 
                          ooc.PlannedOrderItem oi 
                          join ooc.PlannedOrder po on oi.PlannedOrderId = po.Id
                          join RetailVoucher rv on oi.RetailVoucherId = rv.Id
                      where po.PlannedPacketId = @PlannedPacketId
                          and oi.PartnerId is null
                          and oi.OnDmenadServiceId is null
                          and rv.VoucherTypeId = 1
                  ) oib
                  group by oib.Id
              ) rvsum
              on urv.Id = rvsum.id;
  
           &lt;/frame&gt;
      &lt;/executionStack&gt;
      &lt;inputbuf&gt;
  Proc [Database Id = 8 Object Id = 2139922745]    &lt;/inputbuf&gt;
     &lt;/process&gt;
     &lt;process id="processd0db8088" taskpriority="0" logused="10716" waitresource="PAGE: 8:1:778990" waittime="1078" ownerId="12987783115" transactionname="user_transaction" lasttranstarted="2014-04-10T19:07:01.473" XDES="0x144975950" lockMode="S" schedulerid="7" kpid="11172" status="suspended" spid="61" sbid="0" ecid="0" priority="0" trancount="2" lastbatchstarted="2014-04-10T19:07:01.473" lastbatchcompleted="2014-04-10T19:07:01.473" clientapp=".Net SqlClient Data Provider" hostname="ID13115" hostpid="12168" loginname="UVUser" isolationlevel="read committed (2)" xactid="12987783115" currentdb="8" lockTimeout="4294967295" clientoption1="673185824" clientoption2="128056"&gt;
      &lt;executionStack&gt;
       &lt;frame procname="UVSystem.ooc.OfflineOrdersImportPacket" line="294" stmtstart="23548" stmtend="24026" sqlhandle="0x030008006d6796551b829700dda200000100000000000000"&gt;
  update ooc.PlannedBatch 
      set 
          IsCompleted = @True
      from ooc.PlannedBatch pb
          join ooc.PlannedUniversalVoucher puv on puv.PlannedBatchId = pb.Id
          left outer join @DuplicatedVouchers dv on dv.Id = puv.Id
      where dv.Id is null;     &lt;/frame&gt;
      &lt;/executionStack&gt;
      &lt;inputbuf&gt;
  Proc [Database Id = 8 Object Id = 1435920237]    &lt;/inputbuf&gt;
     &lt;/process&gt;
    &lt;/process-list&gt;
    &lt;resource-list&gt;
     &lt;keylock hobtid="72057594084655104" dbid="8" objectname="UVSystem.dbo.RetailVoucher" indexname="PK_RetailVoucher" id="lock10ccbd180" mode="X" associatedObjectId="72057594084655104"&gt;
      &lt;owner-list&gt;
       &lt;owner id="processd0db8088" mode="X"/&gt;
      &lt;/owner-list&gt;
      &lt;waiter-list&gt;
       &lt;waiter id="process894748" mode="S" requestType="wait"/&gt;
      &lt;/waiter-list&gt;
     &lt;/keylock&gt;
     &lt;pagelock fileid="1" pageid="778990" dbid="8" objectname="UVSystem.ooc.PlannedUniversalVoucher" id="lock15ba81480" mode="IX" associatedObjectId="72057594113425408"&gt;
      &lt;owner-list&gt;
       &lt;owner id="process894748" mode="IX"/&gt;
      &lt;/owner-list&gt;
      &lt;waiter-list&gt;
       &lt;waiter id="processd0db8088" mode="S" requestType="wait"/&gt;
      &lt;/waiter-list&gt;
     &lt;/pagelock&gt;
    &lt;/resource-list&gt;
   &lt;/deadlock&gt;
  &lt;/deadlock-list&gt;
  </code></pre>