SQL 服务器数据库:INSERT 查询被等待类型阻塞 LCK_M_IX
SQL Server database: INSERT query blocked with wait type LCK_M_IX
我们的 Java 应用程序通过 cron 作业清理日志 table 中的数据。这是为清理执行的查询:
DELETE FROM AU_TRANSACTIONDATA
WHERE AU_ACTIVITYENDTIME != 0
AND AU_ACTIVITYENDTIME <= 1464570001151
我们在 table 的 AU_ACTIVITYENDTIME
列上有一个索引:
CREATE INDEX [IX_AU_TRANSDATA_ENDTIME]
ON [AU_TRANSACTIONDATA]([AU_ACTIVITYENDTIME]) ON [PRIMARY];
我们的应用程序将交易数据(在我们的应用程序中执行 API 时生成)转储到此 table。这是 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,它本身就是 table。
能否解释一下:
- 为什么在执行
DELETE
日志清理查询时 INSERT 查询被阻止?
LCK_M_IX
等待类型是什么意思,如何解决?
DELETE
查询是锁定整个 table 还是在索引上放置独占 (X) 锁?
我不熟悉 SQL 服务器中的等待和锁定策略,所以在这方面的任何帮助都将不胜感激。
编辑:我们已经尝试过删除块中的数据,即一次删除 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
如果任何给定会话试图对需要独占锁的数据库执行某些操作(例如 INSERT
、UPDATE
、DELETE
),并且在单个事务中,您对超过 5000 行、SQL 执行操作服务器将执行 锁升级.
它不会处理 5000 多个单独的行级锁,而是 独占地锁定 整个 table,所以没有在该事务被提交(或回滚)之前,其他操作 - 甚至 SELECT
查询 - 都是可能的。
我们的 Java 应用程序通过 cron 作业清理日志 table 中的数据。这是为清理执行的查询:
DELETE FROM AU_TRANSACTIONDATA
WHERE AU_ACTIVITYENDTIME != 0
AND AU_ACTIVITYENDTIME <= 1464570001151
我们在 table 的 AU_ACTIVITYENDTIME
列上有一个索引:
CREATE INDEX [IX_AU_TRANSDATA_ENDTIME]
ON [AU_TRANSACTIONDATA]([AU_ACTIVITYENDTIME]) ON [PRIMARY];
我们的应用程序将交易数据(在我们的应用程序中执行 API 时生成)转储到此 table。这是 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,它本身就是 table。
能否解释一下:
- 为什么在执行
DELETE
日志清理查询时 INSERT 查询被阻止? LCK_M_IX
等待类型是什么意思,如何解决?DELETE
查询是锁定整个 table 还是在索引上放置独占 (X) 锁?
我不熟悉 SQL 服务器中的等待和锁定策略,所以在这方面的任何帮助都将不胜感激。
编辑:我们已经尝试过删除块中的数据,即一次删除 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
如果任何给定会话试图对需要独占锁的数据库执行某些操作(例如 INSERT
、UPDATE
、DELETE
),并且在单个事务中,您对超过 5000 行、SQL 执行操作服务器将执行 锁升级.
它不会处理 5000 多个单独的行级锁,而是 独占地锁定 整个 table,所以没有在该事务被提交(或回滚)之前,其他操作 - 甚至 SELECT
查询 - 都是可能的。