记录一次高并发下由索引引发的死锁问题

Posted niceletter

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了记录一次高并发下由索引引发的死锁问题相关的知识,希望对你有一定的参考价值。

先上一个存储过程

CREATE PROCEDURE [dbo].[GetNextIncrease] 
@key varchar(50),
@next int output
as
begin
    begin try
         begin tran
            select @next=NextVal from cfg_increase with(xlock,rowlock)  where [Key]=@key;
            --if @next!=NULL
                begin
                    update cfg_increase set NextVal=(NextVal+1) WHERE [Key]=@key;
                end
            --else
            --    begin
            --        update btlh_dep_hdbh set hd=1 WHERE depid=@depid;
            --    end 
         commit
    end try
    begin catch
        rollback
    end catch
end
GO

根据存储过程生成一个流水号。

表结构:

CREATE TABLE [dbo].[cfg_increase](
    [Id] [INT] IDENTITY(1,1) NOT NULL,
    [Key] [NVARCHAR](255) NOT NULL,
    [NextVal] [INT] NOT NULL,
 CONSTRAINT [PK__cfg_incr__3214EC07351DDF8C] PRIMARY KEY CLUSTERED 
(
    [Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

GO

EXEC sys.sp_addextendedproperty @name=NMS_Description, @value=N自增序列标识 , @level0type=NSCHEMA,@level0name=Ndbo, @level1type=NTABLE,@level1name=Ncfg_increase, @level2type=NCOLUMN,@level2name=NKey
GO

EXEC sys.sp_addextendedproperty @name=NMS_Description, @value=N自增序列下一个值 , @level0type=NSCHEMA,@level0name=Ndbo, @level1type=NTABLE,@level1name=Ncfg_increase, @level2type=NCOLUMN,@level2name=NNextVal
GO

EXEC sys.sp_addextendedproperty @name=NMS_Description, @value=N自定义键自增序列 , @level0type=NSCHEMA,@level0name=Ndbo, @level1type=NTABLE,@level1name=Ncfg_increase
GO

key列上无索引, 脚本根据key 更新表的nextValue。

在高并发下抓取到的一个死锁

<deadlock-list>
 <deadlock victim="process20ec00bc8">
  <process-list>
   <process id="process20ec00bc8" taskpriority="0" logused="16928" waitresource="KEY: 9:72057594111787008 (8194443284a0)" waittime="6494" ownerId="2653399770" 
   transactionname="user_transaction" lasttranstarted="2019-07-22T15:41:26.487" XDES="0xb0ec9790" lockMode="U" schedulerid="8" kpid="0" 
   status="suspended" spid="99" sbid="0" ecid="0" priority="0" trancount="3" lastbatchstarted="2019-07-22T15:41:26.500" 
   lastbatchcompleted="2019-07-22T15:41:26.500" clientapp=".Net SqlClient Data Provider" hostname="iZ5nf507j3o23hZ" hostpid="39352" 
   loginname="sa" isolationlevel="read committed (2)" xactid="2653399770" currentdb="9" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
    <executionStack>
     <frame procname="tengda2019718.dbo.GetNextIncrease" line="11" stmtstart="474" stmtend="606" sqlhandle="0x030009007a829c477a1b57016faa00000100000000000000">
update cfg_increase set NextVal=(NextVal+1) WHERE [Key]=@key;     </frame>
    </executionStack>
    <inputbuf>
Proc [Database Id = 9 Object Id = 1201439354]    </inputbuf>
   </process>
   <process id="process9412988" taskpriority="0" logused="21428" waitresource="KEY: 9:72057594111787008 (a0c936a3c965)" waittime="6502" ownerId="2653399772" 
   transactionname="user_transaction" lasttranstarted="2019-07-22T15:41:26.487" XDES="0xe7e45620" lockMode="X" schedulerid="6" kpid="0" 
   status="suspended" spid="83" sbid="0" ecid="0" priority="0" trancount="2" lastbatchstarted="2019-07-22T15:41:26.500" 
   lastbatchcompleted="2019-07-22T15:41:26.500" clientapp=".Net SqlClient Data Provider" hostname="iZ5nf507j3o23hZ" hostpid="39352" 
   loginname="sa" isolationlevel="read committed (2)" xactid="2653399772" currentdb="9" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
    <executionStack>
     <frame procname="tengda2019718.dbo.GetNextIncrease" line="8" stmtstart="242" stmtend="448" sqlhandle="0x030009007a829c477a1b57016faa00000100000000000000">
select @next=NextVal from cfg_increase with(xlock,rowlock)  where [Key]=@key;
            --if @next!=NULL     </frame>
    </executionStack>
    <inputbuf>
Proc [Database Id = 9 Object Id = 1201439354]    </inputbuf>
   </process>
  </process-list>
  <resource-list>
   <keylock hobtid="72057594111787008" dbid="9" objectname="tengda2019718.dbo.cfg_increase" indexname="PK__cfg_incr__3214EC07351DDF8C" id="lock10fc9ea00" mode="X" associatedObjectId="72057594111787008">
    <owner-list>
     <owner id="process9412988" mode="X"/>
    </owner-list>
    <waiter-list>
     <waiter id="process20ec00bc8" mode="U" requestType="wait"/>
    </waiter-list>
   </keylock>
   <keylock hobtid="72057594111787008" dbid="9" objectname="tengda2019718.dbo.cfg_increase" indexname="PK__cfg_incr__3214EC07351DDF8C" id="lock12e75a280" mode="X" associatedObjectId="72057594111787008">
    <owner-list>
     <owner id="process20ec00bc8" mode="X"/>
    </owner-list>
    <waiter-list>
     <waiter id="process9412988" mode="X" requestType="wait"/>
    </waiter-list>
   </keylock>
  </resource-list>
 </deadlock>
</deadlock-list>

抓取到的另外一个死锁:

<deadlock-list>
 <deadlock victim="processba954c8">
  <process-list>
   <process id="processba954c8" taskpriority="0" logused="16384" waitresource="KEY: 9:72057594111787008 (8194443284a0)" waittime="1495" ownerId="2653399801" transactionname="user_transaction" lasttranstarted="2019-07-22T15:41:26.490" XDES="0x30e6833c0" lockMode="X" schedulerid="11" kpid="0" status="suspended" spid="91" sbid="0" ecid="0" priority="0" trancount="2" lastbatchstarted="2019-07-22T15:41:26.507" lastbatchcompleted="2019-07-22T15:41:26.507" clientapp=".Net SqlClient Data Provider" hostname="iZ5nf507j3o23hZ" hostpid="39352" loginname="sa" isolationlevel="read committed (2)" xactid="2653399801" currentdb="9" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
    <executionStack>
     <frame procname="tengda2019718.dbo.GetNextIncrease" line="8" stmtstart="242" stmtend="448" sqlhandle="0x030009007a829c477a1b57016faa00000100000000000000">
select @next=NextVal from cfg_increase with(xlock,rowlock)  where [Key]=@key;
            --if @next!=NULL     </frame>
    </executionStack>
    <inputbuf>
Proc [Database Id = 9 Object Id = 1201439354]    </inputbuf>
   </process>
   <process id="process20ec00bc8" taskpriority="0" logused="16928" waitresource="KEY: 9:72057594111787008 (8194443284a0)" waittime="1493" ownerId="2653399770" transactionname="user_transaction" lasttranstarted="2019-07-22T15:41:26.487" XDES="0xb0ec9790" lockMode="U" schedulerid="8" kpid="0" status="suspended" spid="99" sbid="0" ecid="0" priority="0" trancount="3" lastbatchstarted="2019-07-22T15:41:26.500" lastbatchcompleted="2019-07-22T15:41:26.500" clientapp=".Net SqlClient Data Provider" hostname="iZ5nf507j3o23hZ" hostpid="39352" loginname="sa" isolationlevel="read committed (2)" xactid="2653399770" currentdb="9" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
    <executionStack>
     <frame procname="tengda2019718.dbo.GetNextIncrease" line="11" stmtstart="474" stmtend="606" sqlhandle="0x030009007a829c477a1b57016faa00000100000000000000">
update cfg_increase set NextVal=(NextVal+1) WHERE [Key]=@key;     </frame>
    </executionStack>
    <inputbuf>
Proc [Database Id = 9 Object Id = 1201439354]    </inputbuf>
   </process>
   <process id="process9412988" taskpriority="0" logused="21428" waitresource="KEY: 9:72057594111787008 (a0c936a3c965)" waittime="1501" ownerId="2653399772" transactionname="user_transaction" lasttranstarted="2019-07-22T15:41:26.487" XDES="0xe7e45620" lockMode="X" schedulerid="6" kpid="0" status="suspended" spid="83" sbid="0" ecid="0" priority="0" trancount="2" lastbatchstarted="2019-07-22T15:41:26.500" lastbatchcompleted="2019-07-22T15:41:26.500" clientapp=".Net SqlClient Data Provider" hostname="iZ5nf507j3o23hZ" hostpid="39352" loginname="sa" isolationlevel="read committed (2)" xactid="2653399772" currentdb="9" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
    <executionStack>
     <frame procname="tengda2019718.dbo.GetNextIncrease" line="8" stmtstart="242" stmtend="448" sqlhandle="0x030009007a829c477a1b57016faa00000100000000000000">
select @next=NextVal from cfg_increase with(xlock,rowlock)  where [Key]=@key;
            --if @next!=NULL     </frame>
    </executionStack>
    <inputbuf>
Proc [Database Id = 9 Object Id = 1201439354]    </inputbuf>
   </process>
  </process-list>
  <resource-list>
   <keylock hobtid="72057594111787008" dbid="9" objectname="tengda2019718.dbo.cfg_increase" indexname="PK__cfg_incr__3214EC07351DDF8C" id="lock10fc9ea00" mode="X" associatedObjectId="72057594111787008">
    <owner-list>
     <owner id="process9412988" mode="X"/>
    </owner-list>
    <waiter-list>
     <waiter id="processba954c8" mode="X" requestType="wait"/>
    </waiter-list>
   </keylock>
   <keylock hobtid="72057594111787008" dbid="9" objectname="tengda2019718.dbo.cfg_increase" indexname="PK__cfg_incr__3214EC07351DDF8C" id="lock10fc9ea00" mode="X" associatedObjectId="72057594111787008">
    <owner-list/>
    <waiter-list>
     <waiter id="process20ec00bc8" mode="U" requestType="wait"/>
    </waiter-list>
   </keylock>
   <keylock hobtid="72057594111787008" dbid="9" objectname="tengda2019718.dbo.cfg_increase" indexname="PK__cfg_incr__3214EC07351DDF8C" id="lock12e75a280" mode="X" associatedObjectId="72057594111787008">
    <owner-list>
     <owner id="process20ec00bc8" mode="X"/>
    </owner-list>
    <waiter-list>
     <waiter id="process9412988" mode="X" requestType="wait"/>
    </waiter-list>
   </keylock>
  </resource-list>
 </deadlock>
</deadlock-list>

分析:因为key列无索引,更新需要使用id聚集索引去更新,导致更新请求更新锁时失败,引发死锁问题,

解决办法:

去除id列的聚集索引 ,在key 上建立聚集索引,更新通过key 更新表,解决问题。。。。

以上是关于记录一次高并发下由索引引发的死锁问题的主要内容,如果未能解决你的问题,请参考以下文章

关于高并发下kafka producer send异步发送耗时问题的分析

深入理解分布式事务,高并发下分布式事务的解决方案

3高并发下Nginx优化

【golang】高并发下TCP常见问题解决方案

每秒 10W 次高并发订单业务,你怎么实现?

高并发由InterruptedException异常引发的思考