【发布时间】:2016-10-02 18:12:15
【问题描述】:
我们的 Java 应用程序通过 cron 作业清理日志表中的数据。这是为清理而执行的查询:
DELETE FROM AU_TRANSACTIONDATA
WHERE AU_ACTIVITYENDTIME != 0
AND AU_ACTIVITYENDTIME <= 1464570001151
我们在此表的AU_ACTIVITYENDTIME 列上有一个索引:
CREATE INDEX [IX_AU_TRANSDATA_ENDTIME]
ON [AU_TRANSACTIONDATA]([AU_ACTIVITYENDTIME]) ON [PRIMARY];
我们的应用程序将事务数据(在我们的应用程序中执行 API 时生成)转储到此表中。这是 INSERT 查询:
INSERT INTO AU_TRANSACTIONDATA (AU_TRANSACTIONID, AU_TRANSACTIONNAME, AU_TRANSACTIONDOMAINID, AU_ACTIVITYNAME, AU_ACTIVITYID, AU_ACTIVITYPID, AU_ACTIVITYTYPE, AU_ACTIVITYSTARTTIME, AU_ACTIVITYENDTIME, AU_ACTIVITYSTATUS, AU_CORRECTDATA, AU_ERRORDATA, AU_USERID, AU_GROUPID, AU_NODENAME, AU_TRANSACTIONDESCRIPTION, AU_SEQUENCEID, AU_TRANSSEQUENCEID)
VALUES (@P0, @P1, @P2, @P3, @P4, @P5, @P6, @P7, @P8, @P9, @P10, @P11, @P12, @P13, @P14, @P15, @P16, @P17)
当日志清理(DELETE查询)和数据处理(INSERT查询)同时发生时,我们面临问题。我们有大约 150 万条记录需要清理,因此删除查询需要一些时间来清理日志记录。但在那段时间里,处理被阻止,没有INSERT 查询通过。
这里是日志:
SPID at Head of Blocking Chain:
SPID [ecid]: 3524 [0]
Blocked by SPID: 0
Client Machine: xxxxx
Client Process ID: 123
Application: jTDS
Login Name: xxxx
Last Batch: 5/30/2016 9:06:56 PM
Wait Type:
Wait Resource:
Wait Time: 00:00:00
Database:
Command Text:
DELETE FROM AU_TRANSACTIONDATA
WHERE AU_ACTIVITYENDTIME != 0 AND AU_ACTIVITYENDTIME <= 1464570001151
----------------------------------------------------------------------
Blocked SPID:
SPID [ecid]: 211 [0]
Client Machine: xxxxx
Client Process ID: 123
Application: jTDS
Login Name: xxxxx
Last Batch: 5/30/2016 9:06:56 PM
Wait Type: LCK_M_IX
Wait Resource: AU_TRANSACTIONDATA.IX_AU_TRANSDATA_ENDTIME
Wait Time: 00:00:24
Database: xxxx
Command Text:
INSERT INTO AU_TRANSACTIONDATA (AU_TRANSACTIONID, AU_TRANSACTIONNAME, AU_TRANSACTIONDOMAINID, AU_ACTIVITYNAME, AU_ACTIVITYID, AU_ACTIVITYPID, AU_ACTIVITYTYPE, AU_ACTIVITYSTARTTIME, AU_ACTIVITYENDTIME, AU_ACTIVITYSTATUS, AU_CORRECTDATA, AU_ERRORDATA, AU_USERID, AU_GROUPID, AU_NODENAME, AU_TRANSACTIONDESCRIPTION, AU_SEQUENCEID, AU_TRANSSEQUENCEID) VALUES ( @P0 , @P1 , @P2 , @P3 , @P4 , @P5 , @P6 , @P7 , @P8 , @P9 , @P10 , @P11 , @P12 , @P13 , @P14 , @P15 , @P16 , @P17 )
日志显示 INSERT 语句正在等待资源 AU_TRANSACTIONDATA.IX_AU_TRANSDATA_ENDTIME(表示索引),等待类型为 LCK_M_IX。在一些日志中,我们看到等待资源是表本身的 AU_TRANSACTIONDATA。
你能解释一下吗:
- 为什么在执行
DELETE日志清理查询时,INSERT 查询会被阻止? -
LCK_M_IX等待类型是什么意思,如何解决? -
DELETE查询是锁定整个表还是在索引上放置排他 (X) 锁定?
我不熟悉 SQL Server 中的等待和锁定策略,因此,如果有这方面的帮助,将不胜感激。
编辑:我们已经尝试删除数据块,即一次删除 10000 行,但没有帮助。这是新的 DELETE 查询:
SET ROWCOUNT 10000
delete_more:
DELETE FROM AU_TRANSACTIONDATA
WHERE AU_ACTIVITYENDTIME != 0 AND AU_ACTIVITYENDTIME <= 1464570001151
IF @@ROWCOUNT > 0 GOTO delete_more
SET ROWCOUNT 0
【问题讨论】:
-
如果任何给定会话尝试对需要锁定的数据库执行某些操作,并且在单个事务中,您正在对超过 5000 行执行
DELETE或UPDATE之类的操作,SQL Server 将执行锁升级 - 它不会处理 5000 多个单独的行级锁,而是独占锁 整个表 b>,因此在该事务被提交(或回滚)之前,其他操作 - 甚至是SELECT查询 - 都不再可能。 -
谢谢 Marc,我认为插入不会被阻止(因为该行甚至在默认隔离级别中都不存在。但我的测试现在证明是其他明智的
-
感谢 Marc 的回复,所以如果我们删除行数 独占锁定 整张桌子?
-
是的,正好 - 单个事务少于 5000 行,SQL Server 将处理单独的行级锁,删除和插入应该能够同时并行工作
-
@TheGameiswar:如果 整个表 被独占锁定(由于
DELETE超过 5000 行),那么什么都不会发生 - 没有SELECT,没有INSERT- 什么都没有。
标签: sql-server database database-deadlocks locks