行级锁和页级锁的区别及其后果 行级锁与页级锁之间的区别在于锁定数据的粒度不同。行级锁是指对数据库中的单个行进行锁定,而页级锁是指对整个数据页进行锁定。 行级锁的主要特点是只锁定需要修改或访问的具体行,其他行可以自由地被其他事务修改或访问。这种锁定方式可以提供更大的并发性,但也可能导致死锁或锁竞争的问题。 页级锁则锁定整个数据页,包括其中的所有行。这种锁定方式可以减少死锁和锁竞争的可能性,但会影响并发性能。 对于后果方面,行级锁可能导致较高的并发性能,但容易发生死锁和锁竞争。页级锁可能降低并发性能,但可以减少死锁和锁竞争的风险。 选择使用哪种锁取决于具体的应用场景和性能需求。通常情况下,行级锁适合读写频繁、并发性要求高的场景,而页级锁适合读操作较多、并发性要求相对较低的场景。

尝试运行维护计划时,我收到以下错误信息: 执行查询""失败,出现以下错误:"表""上的索引""(分区1)无法重新组织,因为已禁用页级锁定。" 我们当前在该索引上启用了行级锁定。我可以启用页级锁定,但不确定后果如何。 我的问题是:这两种锁定方案有什么区别,它们在生产环境中有什么实际影响?
2个回答

执行查询“”失败,出现以下错误:“表“”上的索引“”(分区1)无法重新组织,因为已禁用了页面级锁定。” 维护计划可能正在尝试执行ALTER INDEX REORGANIZE操作,这是一种在线操作。要消除碎片化(页面无序),必须锁定并移动页面,如果已禁用页面锁定,则无法进行此操作。在没有页面锁定的情况下进行碎片整理的唯一方法是锁定整个分区,但这对于REORGANIZE来说是不可能的,因为它只能在线进行。 两种锁定方案有什么区别,以及它们在实际生产中的后果是什么? 您需要了解记录和页面的概念,才能评估禁止某种锁定类型的影响。如果您对SQL Server存储内部机制不熟悉,请先阅读《记录解剖学》和《页面解剖学》。简而言之:
  • rows = 记录
  • 记录存储在8kb的页面中

如果您要更改允许的锁类型:

  • 禁用页面锁 = 仅允许行和表锁
  • 禁用行锁 = 仅允许页面和表锁
  • 同时禁用两者 = 仅允许表锁

我知道有两种情况下禁止某种锁类型可能是有益的。这并不意味着没有其他情况,希望其他人能举出例子。

经常访问但很少更改的查找表 - 通过禁用页面和行级锁,所有读取者将获取一个共享表锁。这比通常在表上获取意向共享锁,然后在页面上获取意向共享锁,最后在特定行或多行上获取共享锁更快/更便宜。

防止特定的死锁场景 - 如果遇到由并发进程引起的频繁位于同一页面上的锁导致的死锁,禁止行锁将导致获取页面锁。只有一个进程可以同时访问该页面,其他进程必须等待。

第一个例子是微观优化,对于一般系统来说,不太可能带来可衡量的好处。第二个例子将解决那个特定的死锁场景,但可能会引入意想不到的副作用,比如在代码的其他部分中破坏并发性能。很难完全评估其影响,请谨慎处理!默认情况下,两者都应启用,并且不应轻易更改,除非有充分的理由。

可能什么都没有。我相信微软比你和我更了解。 我曾经在高并发的 OLTP 系统上工作过,从来没有觉得需要改变设置。 死锁应该重试,因为它们无论如何都会发生。 引用自 SQL Server 存储引擎博客中的一段话,"SQL2005 中的锁升级",这篇文章值得完整阅读。 默认情况下,我们同时启用了行锁和页锁...对于大多数情况,SQL Server 选择行锁粒度,但在适当的情况下可能选择页锁。所以对于你提到的情况,很可能是行锁。在数据库或实例级别上无法关闭页锁。你是否遇到了由于页锁而导致的阻塞? 我认为,如果你只强制使用行锁,那么你将消耗可以更有效地使用在其他地方的资源。如果你的负载足够高以至于这个问题很重要,那么为什么要浪费内存呢?这篇博客文章详细讨论了这个问题。 我怀疑这背后有一些迷信,就像这些例子一样:

+1 但是:在 OLTP 系统中可以预防死锁;我的系统已经连续几个月没有发生死锁,尽管我们每周部署2-3次。 - A-K