【问题标题】:SQL Server deadlock caused by range locks in index索引中的范围锁导致的 SQL Server 死锁
【发布时间】:2015-06-01 14:52:06
【问题描述】:

我遇到这样一种情况,即从 C# ASP.NET Web API 将新记录插入 SQL Server 数据库表时,当多个线程命中时会导致死锁。这是由于初始 SELECT 采用共享范围锁 (RangeS-S),然后当 INSERT 发生时,它被转换为 RangeI-N。

缩写和匿名的死锁 XML 如下所示。

<deadlock-list>
<deadlock victim="process19d91c28">
    <process-list>
        <process id="process19d91c28" taskpriority="0" logused="372" waitresource="KEY: 6:72057594044416000 (ffffffffffff)" waittime="3914" ownerId="1072531" transactionname="user_transaction" lasttranstarted="2015-03-27T15:41:26.670" XDES="0x5faad0d0" lockMode="RangeI-N" schedulerid="3" kpid="4300" status="suspended" spid="58" sbid="0" ecid="0" priority="0" trancount="2" lastbatchstarted="2015-03-27T15:41:26.693" lastbatchcompleted="2015-03-27T15:41:26.693" lastattention="1900-01-01T00:00:00.693" clientapp=".Net SqlClient Data Provider" hostname="MYHOST" hostpid="17300" loginname="MYDOMAIN\XYZ_DB_DEV" isolationlevel="serializable (4)" xactid="1072531" currentdb="6" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
            <executionStack>
                <frame procname="XYZ_Local.dbo.Article_Insert" line="20" stmtstart="1100" stmtend="2372" sqlhandle="0x0300060049c6306a7d37c200b0a3000001000000000000000000000000000000000000000000000000000000">
                    INSERT INTO Article (
                    -- ABREVIATED
                    ) VALUES (
                    -- ABREVIATED
                </frame>
            </executionStack>
            <inputbuf>
                Proc [Database Id = 6 Object Id = 1781581385]
            </inputbuf>
        </process>
        <process id="process3bd3f468" taskpriority="0" logused="372" waitresource="KEY: 6:72057594044416000 (ffffffffffff)" waittime="3916" ownerId="1072527" transactionname="user_transaction" lasttranstarted="2015-03-27T15:41:26.663" XDES="0x5faa73f0" lockMode="RangeI-N" schedulerid="2" kpid="3240" status="suspended" spid="59" sbid="0" ecid="0" priority="0" trancount="2" lastbatchstarted="2015-03-27T15:41:26.690" lastbatchcompleted="2015-03-27T15:41:26.690" lastattention="1900-01-01T00:00:00.690" clientapp=".Net SqlClient Data Provider" hostname="MYHOST" hostpid="17300" loginname="MYDOMAIN\XYZ_DB_DEV" isolationlevel="serializable (4)" xactid="1072527" currentdb="6" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
            <executionStack>
                <frame procname="XYZ_Local.dbo.Article_Insert" line="20" stmtstart="1100" stmtend="2372" sqlhandle="0x0300060049c6306a7d37c200b0a3000001000000000000000000000000000000000000000000000000000000">
                    INSERT INTO Article (
                    -- ABREVIATED

                    ) VALUES (
                    -- ABREVIATED
                </frame>
            </executionStack>
            <inputbuf>
                Proc [Database Id = 6 Object Id = 1781581385]
            </inputbuf>
        </process>
    </process-list>
    <resource-list>
        <keylock hobtid="72057594044416000" dbid="6" objectname="XYZ_Local.dbo.Article" indexname="IX_Article_THEINDEX" id="lock43227700" mode="RangeS-S" associatedObjectId="72057594044416000">
            <owner-list>
                <owner id="process3bd3f468" mode="RangeS-S"/>
                <owner id="process3bd3f468" mode="RangeI-N" requestType="convert"/>
            </owner-list>
            <waiter-list>
                <waiter id="process19d91c28" mode="RangeI-N" requestType="convert"/>
            </waiter-list>
        </keylock>
        <keylock hobtid="72057594044416000" dbid="6" objectname="XYZ_Local.dbo.Article" indexname="IX_Article_THEINDEX" id="lock43227700" mode="RangeS-S" associatedObjectId="72057594044416000">
            <owner-list>
                <owner id="process19d91c28" mode="RangeS-S"/>
                <owner id="process19d91c28" mode="RangeI-N" requestType="convert"/>
            </owner-list>
            <waiter-list>
                <waiter id="process3bd3f468" mode="RangeI-N" requestType="convert"/>
            </waiter-list>
        </keylock>
    </resource-list>
</deadlock>
</deadlock-list>

WITH (UPDLOCK) 添加到初始SELECT '解决'死锁,但它不是很漂亮和有效,与代码中的lock() 相同,因为它在事务期间阻塞所有其他线程。

SET TRANSACTION ISOLATION LEVEL REPEATABLE READ 添加到 Article_Insert SPROC 似乎也可以解决死锁。

我从这个 XML 中看到,隔离级别是 Serializable,我很困惑这是怎么回事。当我运行这段代码时。

SELECT *
FROM [Ecs_Local].[dbo].[Article]
WHERE title ='jcp001'

SELECT CASE transaction_isolation_level 
WHEN 0 THEN 'Unspecified' 
WHEN 1 THEN 'ReadUncommitted' 
WHEN 2 THEN 'ReadCommitted' 
WHEN 3 THEN 'Repeatable' 
WHEN 4 THEN 'Serializable' 
WHEN 5 THEN 'Snapshot' END AS TRANSACTION_ISOLATION_LEVEL 
FROM sys.dm_exec_sessions 
where session_id = @@SPID

响应为ReadCommitted,因此SQL Server 实例上的默认值为ReadCommitted

当我在 c# 代码中构建事务时,我会使用一个实用工具来执行此操作

_transaction = _connection.BeginTransaction(IsolationLevel.Serializable);

我假设这会将整个事务的默认隔离级别设置为可序列化。

我已经研究过重构代码以在事务之外进行初始选择,但这并不直接,也不一定能解决可能同样存在此问题的代码的其他区域。

我想了解的是解决这个问题的最佳方法是什么:

  1. 更改事务在代码中的构建方式,以便它们使用READ COMMITTED 代替(这将适用于我的应用程序中的每个事务)以及潜在的问题是什么(我不明白幻像读取问题)
  2. 将 WITH (UPDLOCK) 添加到各个 SPROCS 以尽早阻止并确保以后不需要锁定转换
  3. 将执行 INSERTS/UPDATES 的单个 SPROCS 中的隔离级别更改为 REPEATABLE READ

编辑 1 按照 Bogdan 的要求,这里是匿名的执行计划

<?xml version="1.0" encoding="utf-16"?>
<ShowPlanXML xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" Version="1.2" Build="12.0.2000.8" xmlns="http://schemas.microsoft.com/sqlserver/2004/07/showplan">
    <BatchSequence>
        <Batch>
            <Statements>
                <StmtSimple StatementCompId="1" StatementId="1" StatementText="Article_Insert" StatementType="EXECUTE PROC" RetrievedFromCache="false" />
            </Statements>
            <Statements>
                <StmtSimple>
                    <StoredProc ProcName="Article_Insert">
                        <Statements>
                            <StmtSimple StatementCompId="2" StatementId="2" StatementText="CREATE PROCEDURE [dbo].[Article_Insert]&#xD;&#xA;    @CurrentUser NVARCHAR(1000),&#xD;&#xA;  @xyzJDocId BIGINT,&#xD;&#xA;    @xyzZDocId BIGINT,&#xD;&#xA;    @ZDocNumber NVARCHAR(255) = NULL,&#xD;&#xA;    @InstutionType NVARCHAR(255),&#xD;&#xA;    @InstutionName NVARCHAR(255) = NULL,&#xD;&#xA;    @QWStatus NVARCHAR(255) = NULL,&#xD;&#xA;   @Doi NVARCHAR(32) = NULL,&#xD;&#xA; @Title NVARCHAR(4000),&#xD;&#xA;    @ArticleType NVARCHAR(255),&#xD;&#xA;   @Active BIT,&#xD;&#xA;    @Exempt BIT,&#xD;&#xA;    @NewDocRequired BIT&#xD;&#xA;AS&#xD;&#xA;BEGIN&#xD;&#xA;    -- ThirdPartyContent    Abc -&gt; xyz only&#xD;&#xA;    -- ConflictOfInterest   Abc -&gt; xyz only&#xD;&#xA;&#xD;&#xA;  SET TRANSACTION ISOLATION LEVEL REPEATABLE READ&#xD;&#xA;&#xD;&#xA; " StatementType="SET TRANSACTION ISOLATION LEVEL" RetrievedFromCache="true" />
                            <StmtSimple StatementCompId="3" StatementEstRows="1" StatementId="3" StatementOptmLevel="TRIVIAL" CardinalityEstimationModelVersion="120" StatementSubTreeCost="0.0300044" StatementText="INSERT INTO Article (&#xD;&#xA;       [CreatedDate], &#xD;&#xA;        [LastModifiedBy],&#xD;&#xA;        [xyzJDocId],    &#xD;&#xA;      [xyzZDocId],&#xD;&#xA;      [ZDocNumber],&#xD;&#xA;        [InstutionType],&#xD;&#xA;        [InstutionName],&#xD;&#xA;        [QWStatus],&#xD;&#xA;        [Doi],&#xD;&#xA;        [Title],&#xD;&#xA;      [ArticleType],&#xD;&#xA;        [Active],&#xD;&#xA;        [Exempt],&#xD;&#xA;        [NewDocRequired]&#xD;&#xA;    ) VALUES (&#xD;&#xA;        GETUTCDATE(),&#xD;&#xA;        @CurrentUser,&#xD;&#xA;      @xyzJDocId,&#xD;&#xA;       @xyzZDocId,&#xD;&#xA;       @ZDocNumber,&#xD;&#xA;        @InstutionType,&#xD;&#xA;        @InstutionName,&#xD;&#xA;        @QWStatus,&#xD;&#xA;        @Doi,&#xD;&#xA;     @Title,&#xD;&#xA;       @ArticleType,&#xD;&#xA;        @Active,&#xD;&#xA;        @Exempt,&#xD;&#xA;        @NewDocRequired&#xD;&#xA;    )" StatementType="INSERT" QueryHash="0x108916B56B42574E" QueryPlanHash="0x73B019D9C6F1A1C5" RetrievedFromCache="true">
                                <StatementSetOptions ANSI_NULLS="true" ANSI_PADDING="true" ANSI_WARNINGS="true" ARITHABORT="true" CONCAT_NULL_YIELDS_NULL="true" NUMERIC_ROUNDABORT="false" QUOTED_IDENTIFIER="true" />
                                <QueryPlan CachedPlanSize="32" CompileTime="1" CompileCPU="1" CompileMemory="176">
                                    <MemoryGrantInfo SerialRequiredMemory="0" SerialDesiredMemory="0" />
                                    <OptimizerHardwareDependentProperties EstimatedAvailableMemoryGrant="38400" EstimatedPagesCached="9600" EstimatedAvailableDegreeOfParallelism="2" />
                                    <RelOp AvgRowSize="9" EstimateCPU="3E-06" EstimateIO="0.03" EstimateRebinds="0" EstimateRewinds="0" EstimatedExecutionMode="Row" EstimateRows="1" LogicalOp="Insert" NodeId="0" Parallel="false" PhysicalOp="Clustered Index Insert" EstimatedTotalSubtreeCost="0.0300044">
                                        <OutputList />
                                        <Update DMLRequestSort="false">
                                            <Object Database="[XYZ_Local]" Schema="[dbo]" Table="[Article]" Index="[PK__tmp_ms_x__3214EC071788A4DB]" IndexKind="Clustered" Storage="RowStore" />
                                            <Object Database="[XYZ_Local]" Schema="[dbo]" Table="[Article]" Index="[IX_Article_THEINDEX]" IndexKind="NonClustered" Storage="RowStore" />
                                            <Object Database="[XYZ_Local]" Schema="[dbo]" Table="[Article]" Index="[IX_Article_OTHERINDEX]" IndexKind="NonClustered" Storage="RowStore" />
                                            <SetPredicate>
                                                <ScalarOperator ScalarString="[XYZ_Local].[dbo].[Article].[CreatedDate] = RaiseIfNullInsert([Expr1003]),[XYZ_Local].[dbo].[Article].[LastModifiedBy] = RaiseIfNullInsert([@CurrentUser]),[XYZ_Local].[dbo].[Article].[xyzJDocId] = RaiseIfNullInsert([@xyzJDocId]),[XYZ_Local].[dbo].[Article].[xyzZDocId] = RaiseIfNullInsert([@xyzZDocId]),[XYZ_Local].[dbo].[Article].[ZDocNumber] = [@ZDocNumber],[XYZ_Local].[dbo].[Article].[InstutionType] = [@InstutionType],[XYZ_Local].[dbo].[Article].[InstutionName] = [@InstutionName],[XYZ_Local].[dbo].[Article].[QWStatus] = [@QWStatus],[XYZ_Local].[dbo].[Article].[Doi] = [@Doi],[XYZ_Local].[dbo].[Article].[Title] = RaiseIfNullInsert([@Title]),[XYZ_Local].[dbo].[Article].[ArticleType] = RaiseIfNullInsert([@ArticleType]),[XYZ_Local].[dbo].[Article].[Active] = RaiseIfNullInsert([@Active]),[XYZ_Local].[dbo].[Article].[Exempt] = RaiseIfNullInsert([@Exempt]),[XYZ_Local].[dbo].[Article].[NewDocRequired] = RaiseIfNullInsert([@NewDocRequired]),[XYZ_Local].[dbo].[Article].[Id] = [Expr1002],[XYZ_Local].[dbo].[Article].[ThirdPartyContent] = NULL,[XYZ_Local].[dbo].[Article].[ConflictOfInterest] = NULL">
                                                    <ScalarExpressionList>
                                                        <ScalarOperator>
                                                            <MultipleAssign>
                                                                <Assign>
                                                                    <ColumnReference Database="[XYZ_Local]" Schema="[dbo]" Table="[Article]" Column="CreatedDate" />
                                                                    <ScalarOperator>
                                                                        <Intrinsic FunctionName="RaiseIfNullInsert">
                                                                            <ScalarOperator>
                                                                                <Identifier>
                                                                                    <ColumnReference Column="Expr1003" />
                                                                                </Identifier>
                                                                            </ScalarOperator>
                                                                        </Intrinsic>
                                                                    </ScalarOperator>
                                                                </Assign>
                                                                <Assign>
                                                                    <ColumnReference Database="[XYZ_Local]" Schema="[dbo]" Table="[Article]" Column="LastModifiedBy" />
                                                                    <ScalarOperator>
                                                                        <Intrinsic FunctionName="RaiseIfNullInsert">
                                                                            <ScalarOperator>
                                                                                <Identifier>
                                                                                    <ColumnReference Column="@CurrentUser" />
                                                                                </Identifier>
                                                                            </ScalarOperator>
                                                                        </Intrinsic>
                                                                    </ScalarOperator>
                                                                </Assign>
                                                                <Assign>
                                                                    <ColumnReference Database="[XYZ_Local]" Schema="[dbo]" Table="[Article]" Column="xyzJDocId" />
                                                                    <ScalarOperator>
                                                                        <Intrinsic FunctionName="RaiseIfNullInsert">
                                                                            <ScalarOperator>
                                                                                <Identifier>
                                                                                    <ColumnReference Column="@xyzJDocId" />
                                                                                </Identifier>
                                                                            </ScalarOperator>
                                                                        </Intrinsic>
                                                                    </ScalarOperator>
                                                                </Assign>
                                                                <Assign>
                                                                    <ColumnReference Database="[XYZ_Local]" Schema="[dbo]" Table="[Article]" Column="xyzZDocId" />
                                                                    <ScalarOperator>
                                                                        <Intrinsic FunctionName="RaiseIfNullInsert">
                                                                            <ScalarOperator>
                                                                                <Identifier>
                                                                                    <ColumnReference Column="@xyzZDocId" />
                                                                                </Identifier>
                                                                            </ScalarOperator>
                                                                        </Intrinsic>
                                                                    </ScalarOperator>
                                                                </Assign>
                                                                <Assign>
                                                                    <ColumnReference Database="[XYZ_Local]" Schema="[dbo]" Table="[Article]" Column="ZDocNumber" />
                                                                    <ScalarOperator>
                                                                        <Identifier>
                                                                            <ColumnReference Column="@ZDocNumber" />
                                                                        </Identifier>
                                                                    </ScalarOperator>
                                                                </Assign>
                                                                <Assign>
                                                                    <ColumnReference Database="[XYZ_Local]" Schema="[dbo]" Table="[Article]" Column="InstutionType" />
                                                                    <ScalarOperator>
                                                                        <Identifier>
                                                                            <ColumnReference Column="@InstutionType" />
                                                                        </Identifier>
                                                                    </ScalarOperator>
                                                                </Assign>
                                                                <Assign>
                                                                    <ColumnReference Database="[XYZ_Local]" Schema="[dbo]" Table="[Article]" Column="InstutionName" />
                                                                    <ScalarOperator>
                                                                        <Identifier>
                                                                            <ColumnReference Column="@InstutionName" />
                                                                        </Identifier>
                                                                    </ScalarOperator>
                                                                </Assign>
                                                                <Assign>
                                                                    <ColumnReference Database="[XYZ_Local]" Schema="[dbo]" Table="[Article]" Column="QWStatus" />
                                                                    <ScalarOperator>
                                                                        <Identifier>
                                                                            <ColumnReference Column="@QWStatus" />
                                                                        </Identifier>
                                                                    </ScalarOperator>
                                                                </Assign>
                                                                <Assign>
                                                                    <ColumnReference Database="[XYZ_Local]" Schema="[dbo]" Table="[Article]" Column="Doi" />
                                                                    <ScalarOperator>
                                                                        <Identifier>
                                                                            <ColumnReference Column="@Doi" />
                                                                        </Identifier>
                                                                    </ScalarOperator>
                                                                </Assign>
                                                                <Assign>
                                                                    <ColumnReference Database="[XYZ_Local]" Schema="[dbo]" Table="[Article]" Column="Title" />
                                                                    <ScalarOperator>
                                                                        <Intrinsic FunctionName="RaiseIfNullInsert">
                                                                            <ScalarOperator>
                                                                                <Identifier>
                                                                                    <ColumnReference Column="@Title" />
                                                                                </Identifier>
                                                                            </ScalarOperator>
                                                                        </Intrinsic>
                                                                    </ScalarOperator>
                                                                </Assign>
                                                                <Assign>
                                                                    <ColumnReference Database="[XYZ_Local]" Schema="[dbo]" Table="[Article]" Column="ArticleType" />
                                                                    <ScalarOperator>
                                                                        <Intrinsic FunctionName="RaiseIfNullInsert">
                                                                            <ScalarOperator>
                                                                                <Identifier>
                                                                                    <ColumnReference Column="@ArticleType" />
                                                                                </Identifier>
                                                                            </ScalarOperator>
                                                                        </Intrinsic>
                                                                    </ScalarOperator>
                                                                </Assign>
                                                                <Assign>
                                                                    <ColumnReference Database="[XYZ_Local]" Schema="[dbo]" Table="[Article]" Column="Active" />
                                                                    <ScalarOperator>
                                                                        <Intrinsic FunctionName="RaiseIfNullInsert">
                                                                            <ScalarOperator>
                                                                                <Identifier>
                                                                                    <ColumnReference Column="@Active" />
                                                                                </Identifier>
                                                                            </ScalarOperator>
                                                                        </Intrinsic>
                                                                    </ScalarOperator>
                                                                </Assign>
                                                                <Assign>
                                                                    <ColumnReference Database="[XYZ_Local]" Schema="[dbo]" Table="[Article]" Column="Exempt" />
                                                                    <ScalarOperator>
                                                                        <Intrinsic FunctionName="RaiseIfNullInsert">
                                                                            <ScalarOperator>
                                                                                <Identifier>
                                                                                    <ColumnReference Column="@Exempt" />
                                                                            </Identifier>
                                                                        </ScalarOperator>
                                                                    </Intrinsic>
                                                                </ScalarOperator>
                                                            </Assign>
                                                            <Assign>
                                                                <ColumnReference Database="[XYZ_Local]" Schema="[dbo]" Table="[Article]" Column="NewDocRequired" />
                                                                <ScalarOperator>
                                                                    <Intrinsic FunctionName="RaiseIfNullInsert">
                                                                        <ScalarOperator>
                                                                            <Identifier>
                                                                                <ColumnReference Column="@NewDocRequired" />
                                                                            </Identifier>
                                                                        </ScalarOperator>
                                                                    </Intrinsic>
                                                                </ScalarOperator>
                                                            </Assign>
                                                            <Assign>
                                                                <ColumnReference Database="[XYZ_Local]" Schema="[dbo]" Table="[Article]" Column="Id" />
                                                                <ScalarOperator>
                                                                    <Identifier>
                                                                        <ColumnReference Column="Expr1002" />
                                                                    </Identifier>
                                                                </ScalarOperator>
                                                            </Assign>
                                                            <Assign>
                                                                <ColumnReference Database="[XYZ_Local]" Schema="[dbo]" Table="[Article]" Column="ThirdPartyContent" />
                                                                <ScalarOperator>
                                                                    <Const ConstValue="NULL" />
                                                                </ScalarOperator>
                                                            </Assign>
                                                            <Assign>
                                                                <ColumnReference Database="[XYZ_Local]" Schema="[dbo]" Table="[Article]" Column="ConflictOfInterest" />
                                                                <ScalarOperator>
                                                                    <Const ConstValue="NULL" />
                                                                </ScalarOperator>
                                                            </Assign>
                                                        </MultipleAssign>
                                                    </ScalarOperator>
                                                </ScalarExpressionList>
                                            </ScalarOperator>
                                        </SetPredicate>
                                        <RelOp AvgRowSize="19" EstimateCPU="1E-07" EstimateIO="0" EstimateRebinds="0" EstimateRewinds="0" EstimatedExecutionMode="Row" EstimateRows="1" LogicalOp="Compute Scalar" NodeId="1" Parallel="false" PhysicalOp="Compute Scalar" EstimatedTotalSubtreeCost="1.357E-06">
                                            <OutputList>
                                                <ColumnReference Column="Expr1002" />
                                                <ColumnReference Column="Expr1003" />
                                            </OutputList>
                                            <ComputeScalar>
                                                <DefinedValues>
                                                    <DefinedValue>
                                                        <ColumnReference Column="Expr1003" />
                                                        <ScalarOperator ScalarString="getutcdate()">
                                                            <Identifier>
                                                                <ColumnReference Column="ConstExpr1004">
                                                                    <ScalarOperator>
                                                                        <Intrinsic FunctionName="getutcdate" />
                                                                    </ScalarOperator>
                                                                </ColumnReference>
                                                            </Identifier>
                                                        </ScalarOperator>
                                                    </DefinedValue>
                                                </DefinedValues>
                                                <RelOp AvgRowSize="11" EstimateCPU="1E-07" EstimateIO="0" EstimateRebinds="0" EstimateRewinds="0" EstimatedExecutionMode="Row" EstimateRows="1" LogicalOp="Compute Scalar" NodeId="2" Parallel="false" PhysicalOp="Compute Scalar" EstimatedTotalSubtreeCost="1.257E-06">
                                                    <OutputList>
                                                        <ColumnReference Column="Expr1002" />
                                                    </OutputList>
                                                    <ComputeScalar ComputeSequence="true">
                                                        <DefinedValues>
                                                            <DefinedValue>
                                                                <ColumnReference Column="Expr1002" />
                                                                <ScalarOperator ScalarString="getidentity((880722190),(6),NULL)">
                                                                    <Intrinsic FunctionName="getidentity">
                                                                        <ScalarOperator>
                                                                            <Const ConstValue="(880722190)" />
                                                                        </ScalarOperator>
                                                                        <ScalarOperator>
                                                                            <Const ConstValue="(6)" />
                                                                        </ScalarOperator>
                                                                        <ScalarOperator>
                                                                            <Const ConstValue="NULL" />
                                                                        </ScalarOperator>
                                                                    </Intrinsic>
                                                                </ScalarOperator>
                                                            </DefinedValue>
                                                        </DefinedValues>
                                                        <RelOp AvgRowSize="9" EstimateCPU="1.157E-06" EstimateIO="0" EstimateRebinds="0" EstimateRewinds="0" EstimatedExecutionMode="Row" EstimateRows="1" LogicalOp="Constant Scan" NodeId="3" Parallel="false" PhysicalOp="Constant Scan" EstimatedTotalSubtreeCost="1.157E-06">
                                                            <OutputList />
                                                            <ConstantScan />
                                                        </RelOp>
                                                    </ComputeScalar>
                                                </RelOp>
                                            </ComputeScalar>
                                        </RelOp>
                                    </Update>
                                </RelOp>
                                <ParameterList>
                                    <ColumnReference Column="@NewDocRequired" ParameterCompiledValue="(0)" />
                                    <ColumnReference Column="@Exempt" ParameterCompiledValue="(0)" />
                                    <ColumnReference Column="@Active" ParameterCompiledValue="(1)" />
                                    <ColumnReference Column="@ArticleType" ParameterCompiledValue="N'Article'" />
                                    <ColumnReference Column="@Title" ParameterCompiledValue="N'jcp001'" />
                                    <ColumnReference Column="@Doi" ParameterCompiledValue="NULL" />
                                    <ColumnReference Column="@QWStatus" ParameterCompiledValue="NULL" />
                                    <ColumnReference Column="@InstutionName" ParameterCompiledValue="NULL" />
                                    <ColumnReference Column="@InstutionType" ParameterCompiledValue="N'Cogent'" />
                                    <ColumnReference Column="@ZDocNumber" ParameterCompiledValue="NULL" />
                                    <ColumnReference Column="@xyzZDocId" ParameterCompiledValue="(2015032810025104)" />
                                    <ColumnReference Column="@xyzJDocId" ParameterCompiledValue="(852)" />
                                    <ColumnReference Column="@CurrentUser" ParameterCompiledValue="N'Abc\Api'" />
                                </ParameterList>
                            </QueryPlan>
                        </StmtSimple>
                        <StmtSimple StatementCompId="4" StatementId="4" StatementText="&#xD;&#xA;&#xD;&#xA; SELECT SCOPE_IDENTITY() AS [ArticleId]" StatementType="SELECT WITHOUT QUERY" RetrievedFromCache="true" />
                    </Statements>
                </StoredProc>
            </StmtSimple>
        </Statements>
    </Batch>
</BatchSequence>

【问题讨论】:

  • 你需要什么并发保证? SELECT 是否必须与 INSERT 一致?例如,如果您使用两个事务,则不会。
  • [1] 在 SSMS 中执行以下语句 SELECT OBJECT_NAME(1781581385, 6):它会给出导致此死锁的存储过程的名称(可能是 dbo.Article_Insert),[2] 在SSMS 因此:Ctrl + M(包括实际执行计划),F5(执行)[3] 在此处或在 pastebin 上发布实际执行计划(以 XML 格式)。
  • @BogdanSahlean。我将根据要求将执行添加到问题中。
  • @usr,我想我认为只要我们正在读取提交的数据,那么在这种情况下 SELECT 就可以与 INSERTS 不一致。
  • @BogdanSahlean,感谢您的帮助。非常感激。我现在已正确遵循您的指示(抱歉!)并制定了执行计划,但可以将其包含在正文中,因为它太长(限制为 30k 字符)。有什么想法可以发布吗?现在我把它放在这里:drive.google.com/file/d/0By2Xzv6Jmt7DUlNmcS1SU0hVMEE 但理想情况下希望将它作为这个问题的一部分。

标签: c# sql-server multithreading deadlock database-deadlocks


【解决方案1】:

由于可序列化的隔离级别,S 锁由 select 使用。可序列化的意思是“好像串行执行”,在 SQL Server 中,它要求所有读取的数据都稳定。

您似乎不需要它,因此您可能应该降级隔离级别。

快照隔离级别通常非常适合许多应用。您可以获得完美的读取一致性,读取数据的锁定为零并且现有锁没有阻塞(这里谈到行锁 - 请将此语句作为近似信息)。

数字 3(使用可重复读取)没有帮助,因为您无法减少 DML 占用的锁。隔离级别(几乎)没有影响。

请告诉我你的想法。回答这样的问题总是很困难,因为“最佳”解决方案在很大程度上取决于具体情况。如果适用,我总是推荐 SI,因为它是对广泛问题的全面解决方案。

【讨论】:

  • 感谢您的意见。 “降级隔离级别”是指在 SPROC 级别还是在事务启动时?
  • 没关系。重要的是在相关语句运行时设置的隔离级别。你如何实现这一点并不重要。通常,整个应用程序不可能有一个 iso 级别,因为不同的操作有不同的要求。因此,在 proc 中设置 iso 级别似乎是合理的。
  • 考虑另一种策略:使用可序列化(这是一个非常容易理解并且具有完美一致性的级别)并使用死锁重试。重试是解决几乎总是有效的死锁的有效解决方案。
  • 我已经改变了策略,因为我对改变隔离级别感到不安。谢谢。
最近更新 更多