先上一个存储过程
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=N'MS_Description', @value=N'自增序列标识' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'cfg_increase', @level2type=N'COLUMN',@level2name=N'Key' GO EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'自增序列下一个值' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'cfg_increase', @level2type=N'COLUMN',@level2name=N'NextVal' GO EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'自定义键自增序列' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'cfg_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="td2019718.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="td2019718.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="td2019718.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="td2019718.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="td2019718.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="td2019718.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="td2019718.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="td2019718.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="td2019718.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="td2019718.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 更新表,解决问题。。。。