【问题标题】:SQL Server lock escalation issueSQL Server 锁升级问题
【发布时间】:2009-05-16 16:17:40
【问题描述】:

我正在阅读来自MSDN Page about SQL Server lock escalation 的 SQL Server 锁升级

我的问题是,锁升级的主要原因似乎是减少维护更多锁的开销(例如,当为表获取更多行锁时,行级锁升级到表级)。我的问题是,保持更多的锁会提高并发性,这是一个好处,为什么是开销?在我的拙见中,锁应该足够小,以通过提高并发性来提高数据库性能。谁能简单地解释一下为什么需要锁升级以及所谓的锁开销是什么?

提前致谢, 乔治

【问题讨论】:

    标签: sql-server locking escalation


    【解决方案1】:

    谁能简单地解释一下为什么需要锁升级以及所谓的锁开销是什么?

    当你更新一张表并锁定一行时,你需要以某种方式记录这个事实:那是一行,它已被更新并锁定。

    当你更新百万行时,你需要做这百万次,因此有一些空间来保存百万锁。

    SQL Server 在内存中保存一个锁列表,而 Oracle 在表空间中保存。

    这可能是因为 Oracle 比较老(比我老),而 SQL Server 比 Oracle 还年轻。

    从设计师的角度来看,将临时资源(如锁)保存在永久存储中并不是那么明显的解决方案。只提一件事:您可能需要磁盘写入才能执行SELECT FOR UPDATE

    Oracle 的核心功能是在 80 年代初期开发的,当时根本无法选择将内容保存在内存中。他们只是不得不以某种方式使用磁盘空间。

    如果要使用磁盘空间,则必须在磁盘的某处放置一个锁。

    如果不在行本身内,在哪里为行保留锁?

    SQL Server 锁系统的开发人员在发明名为 Sybase 的 RDBMS 设计时,决定将临时的东西(即锁)存储在临时存储器(即 RAM)中。

    但 Oracle 的设计总是平衡的:如果你的数据库中有 1,000,000 行,那么你就有 1,000,000 把锁的存储空间,如果你有 10 亿行,你可能会存储 10 亿把锁等等。

    SQL Server 的设计在这个意义上是有缺陷的,因为您的 RAM 和 HDD 空间可能不平衡。您可能很容易拥有 16M 的 RAM 和几 TB 的磁盘空间。而你的记忆就是无法拥有所有的锁。

    这就是为什么当锁计数达到一定限制时,SQL Server 决定升级锁:它不是为数据页中的 10 个单独的行(需要 10 条记录)保持锁,而是锁定整个数据页(需要 1 条记录)。

    另一方面,Oracle 在更新行时,只是将锁直接写入数据页。

    这就是为什么 Oracle 的锁是行级的。

    Oracle 不会按照常识“管理”锁:例如,您无法获取 Oracle 中锁定页面的列表。

    当一个事务需要更新一行时,它只是去该行看看它是否被锁定。

    如果是,它会查看哪个事务持有锁(此信息包含在数据页的锁描述符中)并将自身添加到该事务的通知队列中:当锁定事务终止时,原始事务会收到通知并锁定数据。

    从并发的角度来看,锁升级完全是穷人的解决方案:它不会增加并发性。比如说,你可以锁定你甚至没有碰过的行。

    从性能的角度来看,在内存中做事当然比在磁盘上做事要快。

    但是由于Oracle缓存了数据块,并且上述实际操作无论如何都是在内存中执行的,所以性能是相同或接近的。

    【讨论】:

    • 我仍然认为更多的锁会提高并发性——这将提高整体系统性能。如果最终的整体系统并发性和性能更好,则值得在代码中使用更多的内存和更复杂的逻辑。感谢您是否可以显示示例或更多描述,为什么您认为管理更多锁是开销?也许你的意思是如果更多的锁,整体系统性能会更差?更多描述表示赞赏。
    • 感谢您的 cmets,所以使用更多锁总是会提高并发性的观点是错误的吗?还是说使用更多锁总是会提高性能是错误的?
    • 感谢您更新的 cmets,Quassnoi!我对您在 SQL 和 Oracle 之间的比较感兴趣。您提到 SQL 在内存中的链表中实现,而 Oracle 正在使用数据页。我认为它们的性能应该非常相似——都依靠操作系统分页来自动管理内存/磁盘交换。为什么说Oracle优于SQL?还有什么说明。 :-)
    • 我,Quassnoi,在此确认 Oracle 不使用锁升级,因为它使用数据页来管理行级锁定。我并不是说它在速度方面比使用纯内存更有效(因为它不是),但我肯定地说这种行为首先是对并发更友好,其次是更可预测:你不锁定您不打算锁定的行,并且在您的事务中,您始终可以说出哪些行被您锁定,哪些未被锁定。
    • 顺便说一句:并发和性能通常是对立的。在 MySQL 中,无事务的 MyISAM 比事务的 InnoDB 更快。
    【解决方案2】:

    如果 SQL Server 优化器估计/决定查询将“访问”某个范围内的所有行,那么在该范围内持有单个锁而不是必须协商许多锁(锁必须进行类型测试)。这是除了消耗更少的锁资源(系统范围的资源)之外。

    如果您有一个设计良好的架构和适合您的查询工作负载的索引,并且这些索引会定期维护,那么您就不必担心正在发生的升级。在许多情况下,可以通过适当的覆盖索引来消除阻塞表锁。

    更新:查询的覆盖索引意味着不需要执行对集群的查找,这减少了阻塞插入表的机会。

    【讨论】:

    • 您能否就您的意思添加更多评论“在许多情况下,阻塞表锁可以通过适当的覆盖索引来消除。”请?如果您的意思是在这种情况下消除了升级到表级锁,那么我的困惑是为什么在这种情况下消除了升级到表级锁?
    • 每件事都是有代价的,包括锁。如果持有的锁太多,它会变得很昂贵。它正在杀死服务器。是的,它变得不那么并发了。并发不是我们的目标,而是受硬件限制的更高性能/吞吐量。它在逻辑上是无意义的并发,但在硬件上已经超载了。
    • @Dennis Cheung:这没什么意义。你似乎在说显而易见的事?
    • @Dennis Cheung,我无法想象何时并发更好(使用更多锁时)但系统性能更差。我认为并发就是性能。有什么想法或想法吗?
    【解决方案3】:

    锁开销意味着管理一个表锁比管理大量行锁更好。因为每个锁都占用一些内存,所以很多行锁比一个表锁消耗更多的内存。 所以锁升级从行->页->表锁。

    【讨论】:

    • 你的意思是管理更多的锁会影响性能,从而间接降低并发的好处?或者你的意思是管理更多的锁会直接降低并发性?
    • 顺便说一句:我仍然认为更多的锁会提高并发性——这将提高整体系统性能。如果最终的整体系统并发性和性能更好,则值得在代码中使用更多的内存和更复杂的逻辑。感谢您是否可以显示示例或更多描述,为什么您认为管理更多锁是开销?也许你的意思是如果更多的锁,整体系统性能会更差?更多描述表示赞赏。
    • 是的,更多的锁肯定会影响性能。何时从多个行锁切换到单个页面或表锁完全取决于 sql server 中的内部阈值。您可以强制只使用行锁,但您会发现这会导致性能下降。
    • 我仍然很困惑为什么更多的锁会降低性能。更多的锁意味着更多的并发性,即更好的性能。如果服务器有足够的内存来容纳更多的锁,为什么我们要减少锁的数量并牺牲并发性呢?对不起,我的愚蠢,如果你能用示例场景更详细地表达,不胜感激。
    【解决方案4】:

    “高效”的定义很复杂。有时,如果许多进程可以在没有冲突的情况下进行并发优化,那么优化并发性会更有效。有时,通过临时并发攻击来更快地完成单个进程会更有效。升级锁将阻止其他进程,因此该进程可以完成其工作并让路。

    【讨论】:

    • 如果你能展示一些场景,为什么“阻止其他进程”对整体系统性能有好处?可以这样理解,对非阻塞进程有好处,但是整体性能我就不确定了。
    【解决方案5】:

    有关如何维护锁的具体信息,您可以查看 Microsoft SQL Server 2005: The Storage Engine 的第 8 章(我不隶属于此,这只是我遇到的第一个内部信息)。如果您有一个 books24x7 帐户,它就在那里。它显示在大于 16gb 内存的机器上,锁哈希表中有 2^25 (33554432) 个插槽,上限为 2^31 个插槽。

    对于给定的应用程序,您很可能会发现仅使用细粒度锁的总吞吐量会更高。您可能已经猜到了,这完全取决于锁管理的开销与潜在的过度锁定相比如何。

    【讨论】:

    • 你的意思是当使用更多的锁时,执行更多的内存和锁管理代码,即使更多的并发也会降低系统性能?如果是,我的困惑是,锁管理是纯内存操作,并发管理处理线程上下文切换。线程上下文切换比内存管理昂贵得多。我无法想象锁升级的解决方案会提高性能——更少的内存管理操作所节省的时间与线程上下文切换操作的数量不同。任何更多的见解或 cmets。对不起我愚蠢的想法。 :-)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-01-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多