sal*_*baz 10 database sql-server indexing deadlock
最近我在客户端的OLTP框(Sql server 2005)上遇到了死锁情况,发现它是由两个不同线程调用的两个存储过程引起的.
1,插入在X表中插入数据的sp.
Insert Into X (col1 , col2 , col3 )
Values ('value 1' , 'value 2' , 'value 3' )
Run Code Online (Sandbox Code Playgroud)
2,删除从X表中删除数据的sp.
DELETE X
FROM X T1 WITH (NOLOCK)
INNER JOIN Y T2 WITH (NOLOCK)
ON T1.[col2] = T2.[col2]
WHERE t2.date < 'date time value'
Run Code Online (Sandbox Code Playgroud)
X表有一个唯一的聚簇主键和两个非聚簇的非唯一索引.我通过设置t1222 tace标志来分析死锁,输出总结如下;
插入sp在第1列的非聚集索引上获取了IX锁定.在此期间,删除sp正在等待第1列的同一非聚集索引上的X锁定.
删除sp在第2列的非聚集索引上获取U锁定.在此期间,插入sp正在等待第2列的同一非聚集索引上的IX锁定.
任何想要或建议避免死锁都会非常感激.
编辑
跟踪标志t1222的输出
deadlock-list
deadlock victim=process3c77d68
process-list
process id=process3c12c58 taskpriority=0 logused=1044 waitresource=PAGE: 17:8:7726 waittime=1250 ownerId=5169682909 transactionname=user_transaction lasttranstarted=2011-02-03T03:34:03.443 XDES=0xfe64d78b0 lockMode=IX schedulerid=2 kpid=9544 status=suspended spid=219 sbid=0 ecid=0 priority=0 transcount=2 lastbatchstarted=2011-02-03T03:34:03.457 lastbatchcompleted=2011-02-03T03:34:03.453 clientapp=.Net SqlClient Data Provider hostname=HQMTSRV026 hostpid=3308 loginname=EASUser isolationlevel=read committed (2) xactid=5169682909 currentdb=17 lockTimeout=4294967295 clientoption1=671088672 clientoption2=128056
executionStack
frame procname=adhoc line=1 stmtend=296 sqlhandle=0x0200000084ce2a1d0e95a5623fa3a9c0981d422e33cab999
(@1 int<c/>@2 varchar(8000)<c/>@3 nvarchar(4000))INSERT INTO [VB_Audit_TransactionDetail]([ItemID]<c/>[TransactionID]<c/>[ItemValue]) values(@1<c/>@2<c/>@3)
frame procname=adhoc line=1 stmtend=296 sqlhandle=0x02000000afcb1733f435fb93e13556600acf32bb32e10020
Insert Into VB_Audit_TransactionDetail (ItemID <c/> TransactionID <c/> ItemValue ) Values (4 <c/> '0255978c-f56e-477e-b361-8abe62433cff' <c/> N'HQOLB006' )
frame procname=EAS.dbo.SP_Insert line=13 stmtstart=482 stmtend=522 sqlhandle=0x03001100805efa5997d69400719600000100000000000000
exec (@CommandText)
inputbuf
Proc [Database Id = 17 Object Id = 1509580416]
process id=process3c77d68 taskpriority=0 logused=364 waitresource=PAGE: 17:6:334008 waittime=1234 ownerId=5169682116 transactionname=user_transaction lasttranstarted=2011-02-03T03:34:03.053 XDES=0xa8e297cd0 lockMode=X schedulerid=12 kpid=10300 status=suspended spid=327 sbid=0 ecid=0 priority=0 transcount=2 lastbatchstarted=2011-02-03T03:33:41.137 lastbatchcompleted=2011-02-03T03:33:41.133 clientapp=Microsoft SQL Server hostname=HQSSISSRV002 hostpid=7632 loginname=NBKDOM\SQLCSRVC isolationlevel=read committed (2) xactid=5169682116 currentdb=17 lockTimeout=4294967295 clientoption1=671350816 clientoption2=128056
executionStack
frame procname=EAS.dbo.PurgeAuditTransactionTables line=59 stmtstart=4202 stmtend=4728 sqlhandle=0x030011006354a2313d11ae00979a00000100000000000000
DELETE [dbo].[Audit_TransactionDetail]
FROM [dbo].[Audit_TransactionDetail] T1 WITH (NOLOCK)
INNER JOIN [dbo].[Audit_NBKTransaction] T2 WITH (NOLOCK)ON T1.[TransactionID] = T2.[TransactionID]
WHERE TransactionPostedDateTime < @LastReplicationDateTime
frame procname=adhoc line=1 sqlhandle=0x0100110096968c0560c430ff190000000000000000000000
EXEC PurgeAuditTransactionTables '02 Feb 2011 19:00:13:870'
inputbuf
EXEC PurgeAuditTransactionTables '02 Feb 2011 19:00:13:870'
resource-list
pagelock fileid=8 pageid=7726 dbid=17 objectname=EAS.dbo.Audit_TransactionDetail id=lock4f79500 mode=U associatedObjectId=886415243542528
owner-list
owner id=process3c77d68 mode=U
waiter-list
waiter id=process3c12c58 mode=IX requestType=wait
pagelock fileid=6 pageid=334008 dbid=17 objectname=EAS.dbo.Audit_TransactionDetail id=lock846afca00 mode=IX associatedObjectId=604940266831872
owner-list
owner id=process3c12c58 mode=IX
waiter-list
waiter id=process3c77d68 mode=X requestType=wait
Run Code Online (Sandbox Code Playgroud)
更重要的是一件事; delete和insert语句总是触及2组不同的数据.
而不是发布您对死锁图的理解的描述,而是发布死锁图本身.XML,而不是图形渲染的位图.乍一看,涉及IX锁定存在冲突的事实表明锁定升级正在发生,这表明没有为DELETE提供服务的索引,或者连接上的索引引爆点被命中.但话说回来,这只是由于信息不足而引发的猜测.要提供任何有意义的答案,需要实际的死锁XML以及所涉及对象的确切模式定义.
更新后
您仍然没有提供所请求的信息:所涉及的所有对象的确切模式,包括集群和所有非集群索引定义.在此之前,最初的怀疑仍然存在:DELETE正在进行表扫描,并且已升级为页锁粒度.这是由于索引错误造成的.
您的评估"删除和插入语句总是触及两组不同的数据"在两个帐户上是错误的:
作为旁注,审计表几乎总是需要按事件日期/时间进行聚类,因为对它们的所有查询都要求特定的时间间隔("......和......之间发生的事情")和项目搜索可以通过ID中的非群集主键.清除审计记录(即使在正确聚集时)也存在性能问题,并且需要批处理以避免日志爆炸.最好的解决方案是使用分区部署自动滑动窗口,但这也带来了挑战.
我猜表T2必须非常大.列t2.date是否已编入索引?如果没有,那么大表上的表扫描可能会导致您的问题.索引该列可以通过避免表扫描来优化删除.或者,如果col1或col2上的索引实际上没有被使用(或使用得足够多),丢弃它们也可以避免这个问题.
这些死锁多久发生一次?如果它们非常罕见,那么kludgy解决方案可能就足够了:在try/catch块中包装每个语句,在catch检查中是否错误是由于死锁引起的,如果是,则重试该命令.您也可以仔细用SET DEADLOCK_PRIORITY挑哪个查询将永远赢/输(但你必须与所有呼叫表来平衡这一点).
哦,放弃那些WITH (NOLOCK).插入,更新和删除会忽略NOLOCK.
| 归档时间: |
|
| 查看次数: |
9332 次 |
| 最近记录: |