SQL快照隔离限制

5

对于我的数据库应用程序,采用快照隔离对某些查询事务似乎是解决关键要求的完美选择。

然而,我担心选择快照隔离(我相信必须在整个数据库范围内启用)会在我们开始获得非常高的数据量时带来问题。快照隔离的代价是什么?它是固定成本、线性成本还是几何成本?

如果我对高数据量感到担忧,那么是否有类似于快照隔离的应用程序级功能的策略/模式,可以具有更好的总体性能,但需要更多的时间/专业知识来实现?

谢谢,

Jason

2个回答

10

对于那些不是锁和数据库实现专家的人来说,这可能是一个令人惊讶的难题。

我强烈推荐阅读由Hugo Kornelis(SQL Server MVP)撰写的有关快照隔离的系列文章。到目前为止,这是我见过的关于使用快照时实际考虑的最完整分析。

总结主要问题如下:

  • 当一组并发事务的特定组合可能导致违反约束(UNIQUE,FOREIGN KEY等)时,SQL Server会回退到旧的处理方式。显然,这对可靠性很好,但对性能不好。快照不是万能药,它们不能代替良好的数据库/查询设计和智能锁管理。
  • 快照和触发器可能无法兼容。如果您使用触发器保护数据完整性,则特别危险,但即使您没有这样做,几乎所有触发器都必须变得适用于快照。

根据您编写查询的方式,甚至可能无需使用触发器就会出现意外或不一致的结果

我不知道成本是否固定或线性,尽管它们肯定不是几何级别的; 无论如何,这都会带来一些麻烦。通常被称为“点火并忘记”选项,但事实上,如果您不知道自己在做什么,可能会出现破坏性变化(您可能直到太迟才发现!)。

如果您确定使用它不会引起其他问题,请务必使用它。但是,如果您的任何逻辑都不关心脏读取(这适用于许多系统中超过一半的SELECT查询),则使用READ UNCOMMITTED将获得更好的结果(这需要更多的“专业知识”-您必须非常仔细地考虑会发生什么以及何时发生)。

更新:应用级替代方案

唯一想到的替代方案是缓存。一些数据框架可以为您执行此操作(NHibernate、EF),在某些情况下,您甚至可能有第三层缓存,例如基于消息输入缓存结果的Web服务,这些结果可能基于几个查询。如果这些查询是只读的且底层数据不经常更改,我认为某种形式的缓存在您的情况下会很有效。设计考虑因素当然是您可以承受的数据量相对于您需要提供的量;如果系统非常并发,则这可能无法扩展。

除此之外,我个人不会选择尝试实现自己的应用程序级事务“层”。也许有些人已经这样做了,但我认为我的有限经验无法与数百或数千名最聪明的设计师在数据库管理系统上工作的20年相竞争。


这是一个很好的答案。我们考虑了READ UNCOMMITTED,但我正在使用快照隔离运行这些查询,这些查询是只读的,并且供“人类消费” - 在同一事务中没有写操作。因此,我更喜欢结果集内部一致性和无锁状态,而不是数据货币性。这听起来像是一个适当的用法吗?...我也在阅读你提供的链接。 - Jason Kleban
此外,是否有应用程序级别的替代方案?不同的隔离级别会产生不同的结果,但是应用程序级别的模式可能只使用已禁用快照的READ COMMITTED隔离就能实现相同的好处。或者这样一个自制尝试会使性能变得更糟。 - Jason Kleban
2
在我看来,学习“读取未提交的数据”应该只在极端情况下使用。如果你真的围绕“读取未提交的数据”构建一个系统,那么你将会面临噩梦般的挑战,我希望我的个人数据不会出现在你的系统中。有很多理由不使用它。它可能会导致不可预测的结果,而不仅仅是脏读。我唯一使用它的时候是当我有一个大型事务正在传输数据,并且我想知道有多少记录已经传输完成。我这样做是临时的。去阅读任何SQL Server专家的文章,看看他们对此的看法。 - Kuberchaun
1
个人而言,我更喜欢有证据支持的做法,而不是由“大师”提供的未经资格认证的“最佳实践”建议。READ UNCOMMITTED恰如其分地说明了它的作用;如果你不知道这意味着什么或者不理解它的影响,请不要使用它。如果在特定情况下您可以接受脏读取,那就没问题了。 - Aaronaught

1

快照隔离级别旨在比其他隔离级别更具有读取性能。通过将数据分离成快照,事务不需要在行上获取锁定,从而防止阻塞和死锁。

然而,它必须将行版本信息写入tempdb数据库。因此,每个事务都应该预计一些写入时间。

就像其他所有事情一样,您的情况将决定这是否对您更具有性能优势。如果您的应用程序是OLTP风格,则如果您的事务容易发生死锁,则可能会大幅提高性能。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接