July 3, 2014 at 10:27 am
I have a insert stored procedure that inserts data with the values passed as parameters to this proc and then call another proc that selects the same data that is inserted. I execute the insert procedure within a transaction(READ COMMITTED). I see deadlocks when multiple processes call the insert stored proc. How can I get around this? Any help is appreciated
code:
*create proc [dbo].[xyz_Insert]
@FixingSource VarChar(60)
,@FixTime DateTime
,@InstrumentId Int
,@Lhs Decimal(18, 14)
,@Rhs Decimal(18, 14)
,@Version Int
,@ChangeTime DateTime
,@ChangeUser VarChar(60)
as
set nocount on
if @Version = 0
set @Version = 1
insert into [TableA] ([FixingSource], [FixTime], [InstrumentId], [Lhs], [Rhs], [Version], [ChangeTime], [ChangeUser])
values (@FixingSource, @FixTime, @InstrumentId, @Lhs, @Rhs, @Version, @ChangeTime, @ChangeUser)
exec [dbo].[xyz_Read]
@FixingSource = @FixingSource
,@FixTime = @FixTime
,@InstrumentId = @InstrumentId
----------
CREATE proc [dbo].[XYZ_Read]
@FixingSource VarChar(60) = null,@FixTime DateTime = null,@InstrumentId Int = null
as
set nocount on
select*
from[TableA]
where(@FixingSource is null or [FixingSource] = @FixingSource)
and(@FixTime is null or [FixTime] = @FixTime)
and(@InstrumentId is null or [InstrumentId] = @InstrumentId)
go*
July 3, 2014 at 10:34 am
To start...
http://sqlinthewild.co.za/index.php/2009/03/19/catch-all-queries/
Can you post the deadlock graph? (you can get it out of the system health extended events session)
Also, https://www.simple-talk.com/sql/performance/sql-server-deadlocks-by-example/
Gail Shaw
Microsoft Certified Master: SQL Server, MVP, M.Sc (Comp Sci)
SQL In The Wild: Discussions on DB performance with occasional diversions into recoverability
July 3, 2014 at 11:00 am
<deadlock>
<victim-list>
<victimProcess id="process4c430c8" />
</victim-list>
<process-list>
<process id="process4c430c8" taskpriority="0" logused="348" waitresource="PAGE: 8:1:1502781 " waittime="147" ownerId="31042786" transactionname="user_transaction" lasttranstarted="2014-07-03T17:01:32.197" XDES="0x377a856a8" lockMode="S" schedulerid="18" kpid="10208" status="suspended" spid="78" sbid="0" ecid="0" priority="0" trancount="1" lastbatchstarted="2014-07-03T17:01:32.200" lastbatchcompleted="2014-07-03T17:01:32.200" lastattention="1900-01-01T00:00:00.200" clientapp=".Net SqlClient Data Provider" hostname="WS7LDN00019343" hostpid="12856" loginname="SRVFXTP" isolationlevel="read committed (2)" xactid="31042786" currentdb="8" lockTimeout="4294967295" clientoption1="673316896" clientoption2="128056">
<executionStack>
<frame procname="FXTP.dbo.FixingSnapshotRepository_LimitOrderFixingSnapshot_Read" line="13" stmtstart="404" sqlhandle="0x03000800a2c1341c533f0d015da3000001000000000000000000000000000000000000000000000000000000">
select*
from[LimitOrderFixingSnapshot]
where(@FixingSource is null or [FixingSource] = @FixingSource)
and(@FixTime is null or [FixTime] = @FixTime)
and(@InstrumentId is null or [InstrumentId] = @InstrumentId) </frame>
<frame procname="FXTP.dbo.FixingSnapshotRepository_LimitOrderFixingSnapshot_Insert" line="17" stmtstart="1122" sqlhandle="0x03000800dbe5281d041317015da3000001000000000000000000000000000000000000000000000000000000">
exec [dbo].[FixingSnapshotRepository_LimitOrderFixingSnapshot_Read]
@FixingSource = @FixingSource
,@FixTime = @FixTime
,@InstrumentId = @InstrumentId </frame>
</executionStack>
<inputbuf>
Proc [Database Id = 8 Object Id = 489219547] </inputbuf>
</process>
<process id="process2c6bc38" taskpriority="0" logused="348" waitresource="PAGE: 8:1:1502782 " waittime="171" ownerId="31042795" transactionname="user_transaction" lasttranstarted="2014-07-03T17:01:32.287" XDES="0x3780916a8" lockMode="S" schedulerid="10" kpid="5768" status="suspended" spid="77" sbid="0" ecid="0" priority="0" trancount="1" lastbatchstarted="2014-07-03T17:01:32.293" lastbatchcompleted="2014-07-03T17:01:32.290" lastattention="1900-01-01T00:00:00.290" clientapp=".Net SqlClient Data Provider" hostname="WS7LDN00019343" hostpid="12856" loginname="SRVFXTP" isolationlevel="read committed (2)" xactid="31042795" currentdb="8" lockTimeout="4294967295" clientoption1="673316896" clientoption2="128056">
<executionStack>
<frame procname="FXTP.dbo.FixingSnapshotRepository_LimitOrderFixingSnapshot_Read" line="13" stmtstart="404" sqlhandle="0x03000800a2c1341c533f0d015da3000001000000000000000000000000000000000000000000000000000000">
select*
from[LimitOrderFixingSnapshot]
where(@FixingSource is null or [FixingSource] = @FixingSource)
and(@FixTime is null or [FixTime] = @FixTime)
and(@InstrumentId is null or [InstrumentId] = @InstrumentId) </frame>
<frame procname="FXTP.dbo.FixingSnapshotRepository_LimitOrderFixingSnapshot_Insert" line="17" stmtstart="1122" sqlhandle="0x03000800dbe5281d041317015da3000001000000000000000000000000000000000000000000000000000000">
exec [dbo].[FixingSnapshotRepository_LimitOrderFixingSnapshot_Read]
@FixingSource = @FixingSource
,@FixTime = @FixTime
,@InstrumentId = @InstrumentId </frame>
</executionStack>
<inputbuf>
Proc [Database Id = 8 Object Id = 489219547] </inputbuf>
</process>
</process-list>
<resource-list>
<pagelock fileid="1" pageid="1502781" dbid="8" subresource="FULL" objectname="FXTP.dbo.LimitOrderFixingSnapshot" id="lock253b8c080" mode="IX" associatedObjectId="72057609976217600">
<owner-list>
<owner id="process2c6bc38" mode="IX" />
</owner-list>
<waiter-list>
<waiter id="process4c430c8" mode="S" requestType="wait" />
</waiter-list>
</pagelock>
<pagelock fileid="1" pageid="1502782" dbid="8" subresource="FULL" objectname="FXTP.dbo.LimitOrderFixingSnapshot" id="lock2b2cfd680" mode="SIX" associatedObjectId="72057609976217600">
<owner-list>
<owner id="process4c430c8" mode="SIX" />
</owner-list>
<waiter-list>
<waiter id="process2c6bc38" mode="S" requestType="wait" />
</waiter-list>
</pagelock>
</resource-list>
</deadlock>
July 3, 2014 at 11:07 am
There is only one index - clustered index. The primary key is made of 3 colums FixingSource, FixTime, InstrumentID.
July 3, 2014 at 12:20 pm
No doubt Gail will fix your problem more elegantly, but here is one idea (untested). In your script:
1) Define a temp table with the same structure as TableA.
2) Call the insert proc, with a modified INSERT clause to include an OUTPUT to the temp table you just created.
3) Modify your read proc to read from the temp table rather than TableA.
4) Drop the temp table - if you're feeling tidy 🙂
The absence of evidence is not evidence of absence
- Martin Rees
The absence of consumable DDL, sample data and desired results is, however, evidence of the absence of my response
- Phil Parkin
July 3, 2014 at 12:42 pm
1) You simply MUST fix the IS NULL OR construct - and do so EVERYWHERE you have it in your code.
2) On the whole I would say that many tables, of more than a few rows anyway, can probably benefit from having at least one non-clustered index on them on something that is "searched/linked" that isn't the clustered index.
3) Non-clustered indexes are one of the main points of attack for resolving deadlock issues. Here's an oldy-but-goodie: http://blogs.msdn.com/bartd/archive/2006/09/09/Deadlock-Troubleshooting_2C00_-Part-1.aspx
Note there are 2 additional parts to this blog series.
Also note that Extended Events can offer a VERY good window into deadlock information.
Best,
Kevin G. Boles
SQL Server Consultant
SQL MVP 2007-2012
TheSQLGuru on googles mail service
July 7, 2014 at 5:14 am
Hi I have modified the query as directed. The filters in the query are on the columns that are part of the clustered index (primary key) so I am not sure if I can do anything further to fine tune the Indexes. I see the same behaviour even if I add a non-clusterd-covering index... Please help.
CREATE proc [dbo].[XYZ_Read]
@FixingSource VarChar(60) = null,@FixTime DateTime = null,@InstrumentId Int = null
as
set nocount on
select*
from[LimitOrderFixingSnapshot]
where([FixingSource] = CASE WHEN @FixingSource IS NULL THEN [FixingSource] ELSE @FixingSource END)
AND ([FixTime] = CASE WHEN @FixTime IS NULL THEN [FixTime] ELSE @FixTime END)
AND ([InstrumentId] = CASE WHEN @InstrumentId IS NULL THEN [InstrumentId] ELSE @InstrumentId END)
July 7, 2014 at 5:24 am
neltonk (7/7/2014)
Hi I have modified the query as directed. The filters in the query are on the columns that are part of the clustered index (primary key) so I am not sure if I can do anything further to fine tune the Indexes. I see the same behaviour even if I add a non-clusterd-covering index... Please help.CREATE proc [dbo].[XYZ_Read]
@FixingSource VarChar(60) = null,@FixTime DateTime = null,@InstrumentId Int = null
as
set nocount on
select*
from[LimitOrderFixingSnapshot]
where([FixingSource] = CASE WHEN @FixingSource IS NULL THEN [FixingSource] ELSE @FixingSource END)
AND ([FixTime] = CASE WHEN @FixTime IS NULL THEN [FixTime] ELSE @FixTime END)
AND ([InstrumentId] = CASE WHEN @InstrumentId IS NULL THEN [InstrumentId] ELSE @InstrumentId END)
Did you take the time to read the link which Gail posted regarding catch-all queries?
The absence of evidence is not evidence of absence
- Martin Rees
The absence of consumable DDL, sample data and desired results is, however, evidence of the absence of my response
- Phil Parkin
July 7, 2014 at 6:20 am
neltonk (7/7/2014)
Hi I have modified the query as directed. The filters in the query are on the columns that are part of the clustered index (primary key) so I am not sure if I can do anything further to fine tune the Indexes. I see the same behaviour even if I add a non-clusterd-covering index... Please help.CREATE proc [dbo].[XYZ_Read]
@FixingSource VarChar(60) = null,@FixTime DateTime = null,@InstrumentId Int = null
as
set nocount on
select*
from[LimitOrderFixingSnapshot]
where([FixingSource] = CASE WHEN @FixingSource IS NULL THEN [FixingSource] ELSE @FixingSource END)
AND ([FixTime] = CASE WHEN @FixTime IS NULL THEN [FixTime] ELSE @FixTime END)
AND ([InstrumentId] = CASE WHEN @InstrumentId IS NULL THEN [InstrumentId] ELSE @InstrumentId END)
As Phil's post implies, your solution did absolutely nothing to remove the IS NULL or problem.
Best,
Kevin G. Boles
SQL Server Consultant
SQL MVP 2007-2012
TheSQLGuru on googles mail service
July 7, 2014 at 10:38 am
Given the situation where we had to put a hot fix asap... This worked brilliantly. We have now time to fine tune the code.
I will now try using the recompile hint / dynamic sql within the code as suggested by Gail and test the impact.
Thanks for your help.
July 7, 2014 at 1:09 pm
TSQLLearner2014 (7/7/2014)
Given the situation where we had to put a hot fix asap... This worked brilliantly. We have now time to fine tune the code.I will now try using the recompile hint / dynamic sql within the code as suggested by Gail and test the impact.
Thanks for your help.
I promise you your CODE did NOT make things "brilliantly faster"!! The simple fact that the sproc was compiled and the next call got you the most-often-fast-plan was what happened. Your IS NULL OR could do the same thing - be fast SOME (or even most) of the time.
Glad to hear you have time to put in a proper fix!!
Best,
Kevin G. Boles
SQL Server Consultant
SQL MVP 2007-2012
TheSQLGuru on googles mail service
July 7, 2014 at 2:32 pm
TheSQLGuru (7/7/2014)
TSQLLearner2014 (7/7/2014)
Given the situation where we had to put a hot fix asap... This worked brilliantly. We have now time to fine tune the code.I will now try using the recompile hint / dynamic sql within the code as suggested by Gail and test the impact.
Thanks for your help.
I promise you your CODE did NOT make things "brilliantly faster"!!
What that change would have done is make the performance consistent. Consistently not great, but consistent.
Gail Shaw
Microsoft Certified Master: SQL Server, MVP, M.Sc (Comp Sci)
SQL In The Wild: Discussions on DB performance with occasional diversions into recoverability
Viewing 12 posts - 1 through 11 (of 11 total)
You must be logged in to reply to this topic. Login to reply