SQL Server deadlock caused by range locks in index
Asked Answered
S

1

6

I have a situation where inserting new records into a SQL Server database table from a C# ASP.NET Web API causes deadlocks when hit with multiple threads. This is caused by an initial SELECT taking a shared range lock (RangeS-S) and then when the INSERT happens it is converted to a RangeI-N.

The abbreviated and anonymised deadlock XML is shown below.

<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>

Adding WITH (UPDLOCK) to the initial SELECT 'solves' the deadlock but its not very pretty and effectively is the same as a lock() in the code as it blocks all other threads for the duration of the transaction.

Adding SET TRANSACTION ISOLATION LEVEL REPEATABLE READ to the Article_Insert SPROC instead also seems to solve the deadlock.

I see from this XML, that the isolation level is Serializable and I am confused as to how this is the case. When I run this code.

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

The response is ReadCommitted, so the default on the SQL Server instance is ReadCommitted.

When I build the transaction in the c# code I use a utility that does this

_transaction = _connection.BeginTransaction(IsolationLevel.Serializable);

I assume this sets the default isolation level for the entire transaction to Serializable.

I have looked at restructuring the code to do the initial select outside the transaction, but that is not straight forward and will not necessarily solve other areas of the code that may also suffer from this problem.

What I'd like to understand is what is the best way to solve this:

  1. Change the way the transactions are built in code so that they use READ COMMITTED instead (This would then apply to every transaction in my app) and what the potential problems are with this (I don't understand the phantom reads issue)
  2. Add WITH (UPDLOCK) to individual SPROCS to block early & ensure lock conversions are not needed later on
  3. Change the isolation level in individual SPROCS that do INSERTS/UPDATES to REPEATABLE READ

EDIT 1 As requested by Bogdan here is the anonomised execution plan

<?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>

Strainer answered 28/3, 2015 at 7:47 Comment(8)
What concurrency guarantees do you need? Does the SELECT have to be consistent with the INSERT? If you use two transactions it would not be, for example.Bennir
[1] Execute in SSMS following statement SELECT OBJECT_NAME(1781581385, 6): it will give you the name of stored procedure which caused this deadlock (maybe it is dbo.Article_Insert ), [2] Execute this stored procedure in SSMS thus: Ctrl + M (Include Actual Execution Plan) , F5 (Execute) [3] Post here or on pastebin the actual execution plan (in XML format).Judiciary
@BogdanSahlean. I will add the execution to the question as requested.Strainer
@usr, I think I think that as long as we are reading committed data then the SELECTcan be inconsistent with the INSERTS in this case.Strainer
@chrisp_68: I need actual execution plan. Above XP is estimated. Read carefully my instructions: in SSMS execute stored procedure thus Ctrl + M, F5.Judiciary
@BogdanSahlean, thanks for your help. Much appreciated. I have now followed your instructions correctly (sorry!) and have the execution plan but can include it in the body because it it too long (limit is 30k chars). Any ideas how I can post it? For now I have put it here: drive.google.com/file/d/0By2Xzv6Jmt7DUlNmcS1SU0hVMEE but ideally would like to have it as part of this question.Strainer
Ok. None of these execution plans explain the RangeS-S locks. Could you add [actual] execution plans for SELECT statement: "This is caused by an initial SELECT taking a shared range lock (RangeS-S)" ?Judiciary
Also, could you tell us what is definition (CREATE ... INDEX ...) for IX_Article_THEINDEX ? Actual execution plan for SELECT contains an Index Scan with parallelism ?Judiciary
B
1

The S-locks are taken by the select because of the serializable isolation level. Serializable means "as if serial execution" which, in SQL Server, requires all data read to be stabilized.

You don't seem to need that so you probably should downgrade the isolation level.

Snapshot isolation levels are often a great fit for many apps. You get perfect read consistency with zero locking of read data and no blocking on existing locks (speaking about row locks here - please take this statement as approximating information).

Number 3 (using repeatable read) does not help because you can't reduce the locks that DML takes. The isolation level has (pretty much) no effect.

Please let me know what you think. Answering questions such as this one is always hard because the "best" solution depends very much on the specific circumstances. I always recommend SI if applicable because it is a total solution to a broad range of issues.

Bennir answered 29/3, 2015 at 10:21 Comment(4)
thanks for the input. By "downgrade the isolation level" do you mean at the SPROC level or when the transaction is started?Strainer
Doesn't matter. What matters is the isolation level that is set when the statements in question run. How you achieve that is not important. Usually, it is not possible to have one iso level for the entire app because different operations have different requirements. Setting the iso level in the proc therefore seems reasonable.Bennir
Consider another strategy: Use serializable (which is a level that is very simple to understand and has perfect consistency) and use retry on deadlock. Retry is a valid solution to deadlocks that almost always works.Bennir
I have gone with changing the strategy instead because I am uneasy about changing the isolation level. Thanks.Strainer

© 2022 - 2024 — McMap. All rights reserved.