【问题标题】:SQL Server database: INSERT query blocked with wait type LCK_M_IXSQL Server 数据库:INSERT 查询被等待类型 LCK_M_IX 阻塞
【发布时间】: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。

你能解释一下吗:

  1. 为什么在执行DELETE 日志清理查询时,INSERT 查询会被阻止?
  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

【问题讨论】:

  • 如果任何给定会话尝试对需要锁定的数据库执行某些操作,并且在单个事务中,您正在对超过 5000 行执行DELETEUPDATE 之类的操作,SQL Server 将执行锁升级 - 它不会处理 5000 多个单独的行级锁,而是独占锁 整个表 b>,因此在该事务被提交(或回滚)之前,其他操作 - 甚至是 SELECT 查询 - 都不再可能。
  • 谢谢 Marc,我认为插入不会被阻止(因为该行甚至在默认隔离级别中都不存在。但我的测试现在证明是其他明智的
  • 感谢 Marc 的回复,所以如果我们删除行数 独占锁定 整张桌子?
  • 是的,正好 - 单个事务少于 5000 行,SQL Server 将处理单独的行级锁,删除和插入应该能够同时并行工作
  • @TheGameiswar:如果 整个表 被独占锁定(由于 DELETE 超过 5000 行),那么什么都不会发生 - 没有 SELECT,没有INSERT - 什么都没有。

标签: sql-server database database-deadlocks locks


【解决方案1】:

如果任何给定会话尝试对需要独占锁的数据库执行某些操作(例如INSERTUPDATEDELETE),并且在单个事务中,您正在执行的操作超过5000 行,SQL Server 将执行锁升级

它不会处理 5000 多个单独的行级锁,而是独占锁定整个表,因此无法进行其他操作 - 甚至是 SELECT 查询直到该事务被提交(或回滚)。

【讨论】:

  • 帮助了,谢谢!如果我们在 DELETE 操作期间关闭自动提交会发生什么?我们正在从表中删除大约 2M 条记录(4500 条记录的块),如果关闭自动提交模式,那么我们会看到一些 INSERT 操作被阻塞并且 SQL 数据库服务器有时变得无响应!但是如果自动提交模式打开,那么一切都会像魅力一样工作。任何帮助将不胜感激。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-04-25
  • 1970-01-01
  • 1970-01-01
  • 2019-05-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多