SQL Server中的永久行级锁定

时间:2013-01-28 08:56:35

标签: sql-server performance tsql locking

我在一个存储过程上的性能非常差,它对一些非常小的表进行了超过一百次(!)的更新,并且似乎所有并发用户都在不断地相互阻塞。

计划在今年晚些时候完全重写proc,但与此同时我想看看我们是否可以通过强制每个受影响的表上的行级锁定来缓解这个问题。

在Sybase上,您可以(或者至少可以在2007年左右)使用此语句强制对表进行行级锁定:

alter table titles lock datarows

在SQL Server上,似乎获得相同效果的唯一方法是在每个更新或插入语句上使用WITH(ROWLOCK)。即便如此,这只是一个可以忽略的暗示。

SQL Server中是否有办法强制(或强烈支持)对给定表的所有更新的行级锁定?

3 个答案:

答案 0 :(得分:9)

首先要确保更新不是表扫描。换句话说,你确实有正确的索引(UPDATE也需要索引......)。经过认真考虑后,确保disable page locks on the index used

ALTER INDEX ... WITH (ALLOW_PAGE_LOCKS = OFF, ALLOW_ROW_LOCKS = ON);

让这个操作与你在摇动一桶TNT和一瓶凝固汽油时给予同样的照顾......


其他信息(来自以下评论):

  • 您可以在聚簇索引上禁用页锁,但是您不能禁用堆上的页锁(因为它们是物理结构的,并且无法在不锁定页面的情况下执行正确的锁定层次结构)。

  • 锁定升级是一个(相关的,但是)不同的主题。如果语句选择行级锁粒度并且它决定在执行期间升级到行集粒度级别,则锁定升级才会出现。确实OP可能实际上是升级的受害者,从我读OP的方式来看,我认为更可能的原因就是缺少索引(即,由于扫描而预先选择高锁粒度,不会触发升级)。

  • 初始粒度级别是对手头任务的引擎估计的结果。如果估计指示必须锁定大量行,则可以选择页面粒度,因为获取大量行锁通常是有问题的。缺少索引会触发扫描,通常会选择页面粒度。

  • 升级也是从行/页到行集(对象)的粒度。首先通过中间页面层面会遇到并发问题,因此使用了“大锤子”。

答案 1 :(得分:0)

您可以使用它来禁用锁定升级:

ALTER TABLE titles SET (LOCK_ESCALATION=DISABLE)

请参阅the docs about lock escalation

答案 2 :(得分:0)

  1. trace flag 1211
  2. 通过alter index
  3. 关闭页面级锁定

    这些2的组合将为您提供行级锁定。除非当然sql会决定直接进入表锁定:) 还有1224标志,但它会忽略你的内存压力请求,1211不会。内存消耗可能会增加大的时间,被警告并做一些用户活动模拟(RML或Benchmark Factory)并运行perfmon来观察。我认识那些过去做过的人。