快照,仍然死锁,ROWLOCK

时间:2009-09-16 15:50:00

标签: sql sql-server tsql

我使用以下代码

在我的数据库中打开了快照隔离
ALTER DATABASE MyDatabase
SET ALLOW_SNAPSHOT_ISOLATION ON

ALTER DATABASE MyDatabase
SET READ_COMMITTED_SNAPSHOT ON

并摆脱了许多僵局。

但是当我需要每小时运行一个脚本来清理100,000多行时,我的数据库仍然会产生死锁。

  • 有没有办法可以避免清理脚本中的死锁,我是否需要在该查询中专门设置ROWLOCK?
  • 有没有办法增加数据库使用的行级锁定数?
  • 如何推广锁?从行级到页面级到表级?

我的删除脚本非常简单:

delete statvalue
from statValue,
(select  dateadd(minute,-60, getdate()) as cutoff_date) cd
where temporaryStat = 1
and entrydate < cutoff_date

目前我正在寻找快速解决方案,但长期解决方案会更好。

非常感谢, Patrikc

3 个答案:

答案 0 :(得分:6)

SNAPSHOT隔离只能缓解(某些)涉及读取的死锁,但它绝对没有什么可以避免写入和写入死锁。如果每小时生成100k +行,即每秒约30次插入,那么删除扫描几乎可以保证与其他写入操作冲突。如果你所做的只是插入,永远不更新,那么删除块,但不是行锁定死锁,但由于表足够大而删除正在进行扫描,引擎可能会为删除选择页锁,因此可能是你得到的僵局。

没有入口日期的索引,删除别无选择,只能扫描整个表格。经常插入顶部并在底部删除的这种表实际上是队列,您应该通过entrydate组织它们。这意味着 entrydate 应该是聚集索引中最左侧的键。该组织允许清楚地分离在桌子末端发生的插入物与在另一端发生的删除。但这是一个相当激进的变化,特别是如果你使用statvalueid来读取这些值。我想你现在有一个基于自动增量字段(StatValueId)的聚簇索引。此外,我假设entrydate和statvalueid是相关的。如果两个假设都为真,那么你应该删除base not statvalueid:找到可以安全删除的最大id,然后删除此id左侧聚集索引上的所有内容:

declare @statvalueidmax int;
select @statvalueidmax = max(statvalueid) 
 from statvalue with (readpast)
 where entrydate <  dateadd(minute,-60, getdate());

delete statvalue
 where statvalueid <= @statvalueidmax;

我做了很多假设,但可能是错的。但这个想法的要点是你必须将插入与删除分开,以便它们不重叠。

答案 1 :(得分:0)

减少(或避免)死锁的方法是批量删除每批次之间的等待时间很短(使用WAITFOR DELAY)

此外,可以通过覆盖索引来缓解死锁。

此代码需要一些声明,仅作为示例(自行承担风险!)。

SELECT  @intRowCount = 1,
    @intErrNo = 0

DECLARE @cutoff_date DATETIME

SET @cutoff_date = dateadd(minute,-60, getdate())

SELECT  @intRowsToDelete = COUNT(*) -- Number of rows to be deleted
FROM dbo.statValue 
WHERE temporaryStat = 1
AND  entrydate < @cutoff_date

WHILE @intRowCount > 0 AND @intErrNo = 0
BEGIN

    SET ROWCOUNT @DEL_ROWCOUNT

    delete statvalue
    FROM dbo.statValue 
    WHERE temporaryStat = 1
    AND  entrydate < @cutoff_date

    SELECT  @intErrNo = @@ERROR, @intRowCount = @@ROWCOUNT

    SET ROWCOUNT 0  -- Reset batch size to "all"

    SELECT  @intRowsToDelete = @intRowsToDelete - @intRowCount

    WAITFOR DELAY '000:00:
 END

我还包括约翰建议不要重复计算日期范围标准。

答案 2 :(得分:0)

请重新编写删除查询,如下所示:

DECLARE @cutoff_date DATETIME

SET @cutoff_date = dateadd(minute,-60, getdate())

delete statvalue
from statValue
where temporaryStat = 1
and entrydate < @cutoff_date

您将看到执行计划中的成本降低