SQL Server数据库:使用等待类型LCK_M_IX阻止INSERT查询

Ama*_*man 2 database sql-server database-deadlocks locks

我们的Java应用程序通过cron作业清除日志表中的数据.以下是为清理而执行的查询:

DELETE FROM AU_TRANSACTIONDATA 
WHERE AU_ACTIVITYENDTIME != 0 
  AND AU_ACTIVITYENDTIME <= 1464570001151
Run Code Online (Sandbox Code Playgroud)

我们在AU_ACTIVITYENDTIME这个表的列上有一个索引:

CREATE INDEX [IX_AU_TRANSDATA_ENDTIME] 
    ON [AU_TRANSACTIONDATA]([AU_ACTIVITYENDTIME]) ON [PRIMARY];
Run Code Online (Sandbox Code Playgroud)

我们的应用程序将事务数据(在我们的应用程序中执行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)
Run Code Online (Sandbox Code Playgroud)

当日志清理(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 )
Run Code Online (Sandbox Code Playgroud)

日志显示INSERT语句正在等待资源AU_TRANSACTIONDATA.IX_AU_TRANSDATA_ENDTIME(表示索引),其等待类型为LCK_M_IX.在某些日志中,我们已经看到等待资源是AU_TRANSACTIONDATA,这是表本身.

你能解释一下这个:

  1. 为什么INSERT查询在DELETE执行日志清理查询时被阻止?
  2. LCK_M_IX等待类型是什么意思以及如何解决?
  3. 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
Run Code Online (Sandbox Code Playgroud)

mar*_*c_s 5

如果任何给定的会话尝试做一些事情,需要独占锁的数据库(如INSERT,UPDATE,DELETE),并在单个事务中,你正在做的操作,以超过5000行,SQL Server将做一个锁升级.

相反的处理5000+独立的行级锁,它会完全锁定整个表,所以没有其他的业务-甚至没有SELECT查询-是可能的了,直到事务被提交(或回滚).