为什么使用READ UNCOMMITTED隔离级别?

时间:2010-03-18 15:30:07

标签: sql-server tsql isolation-level

用简单的英语,使用

有什么缺点和优点
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

在.NET应用程序和报告服务应用程序的查询中?

10 个答案:

答案 0 :(得分:192)

此隔离级别允许脏读。一个事务可能会看到某些其他事务所做的未提交的更改。

为了保持最高级别的隔离,DBMS通常会获取数据锁,这可能会导致并发丢失和高锁定开销。这种隔离级别放松了这个属性。

您可以查看Wikipedia article on READ UNCOMMITTED以获取一些示例并进一步阅读。


你可能也有兴趣查看Jeff Atwood的blog article关于他和他的团队如何解决Stack Overflow早期的死锁问题。杰夫说:

  

nolock危险吗?你能结束吗?   在read uncommitted上读取无效数据?是的,从理论上讲。你会   找不到数据库   建筑宇航员的开始   将ACID科学放在你和所有人身上   但是什么时候拉楼火灾报警器   你告诉他们你想试试nolock。   这是真的:理论是可怕的。但   这就是我的想法:“从理论上说   理论和理论之间没有区别   实践。在实践中有。“

     

我绝不会建议使用nolock   作为一般“有益于你的东西”   蛇油修复任何数据库   你可能遇到的僵局问题。您   应该尝试诊断的来源   问题首先。

     

但实际上,将nolock添加到您绝对知道的查询中是简单的,直截了当的只读事务似乎永远不会导致问题... 只要您知道自己在做什么。< /强>

您可能需要考虑的READ UNCOMMITTED级别的另一种替代方法是READ COMMITTED SNAPSHOT。再次引用杰夫:

  

快照依赖于全新的数据更改跟踪方法......不仅仅是略微的逻辑更改,它还要求服务器以不同的方式处理数据。启用此新数据更改跟踪方法后,它会创建每个数据更改的副本或快照。 通过在争用时读取这些快照而不是实时数据,读取时不再需要共享锁,并且整体数据库性能可能会提高。

答案 1 :(得分:35)

这可用于查看长插入查询的进度,进行任何粗略估计(例如COUNT(*)或粗略SUM(*))等。

换句话说,只要您将脏读取查询视为估计值并且不根据它们做出任何关键决策,脏读取查询返回的结果就可以了。

答案 2 :(得分:32)

我最喜欢的read uncommited用例是调试事务中发生的事情。

在调试器下启动软件,当您逐步执行代码行时,它会打开一个事务并修改您的数据库。代码停止后,您可以打开查询分析器,在读取未提交隔离级别上设置并进行查询以查看发生了什么。

您还可以使用它来查看长时间运行的过程是否卡住或正确更新数据库。

如果您的公司喜欢制作过于复杂的存储过程,那就太棒了。

答案 3 :(得分:22)

优点是在某些情况下可以更快。缺点是结果可能是错误的(尚未提交的数据可能会被返回),并且无法保证结果是可重复的。

如果您关心准确性,请不要使用它。

更多信息在MSDN上:

  

实现脏读或隔离级别0锁定,这意味着不会发出共享锁,也不会遵循独占锁。设置此选项后,可以读取未提交或脏的数据;可以更改数据中的值,并且在事务结束之前,行可以在数据集中显示或消失。此选项与在事务中所有SELECT语句中的所有表上设置NOLOCK具有相同的效果。这是四个隔离级别中限制最少的。

答案 4 :(得分:10)

什么时候可以使用READ UNCOMMITTED

经验法则

良好:大汇总报告显示总计不断变化。

冒险:几乎所有其他内容。

好消息是,大多数只读报告属于 Good 类别。

更多细节......

可以使用它:

  • 几乎所有面向用户的汇总报告,例如当前的非静态数据,例如年初至今的销售情况。 它存在误差范围(可能<0.1%),这远低于其他不确定因素,例如输入错误或只是在几分钟内准确记录数据的随机性。

这可能涵盖了商业智能部门在SSRS中所做的大部分工作。当然,除了前面有$符号的任何东西都是例外。许多人的钱比热情高于应用于为客户提供服务并产生这些钱所需的相关核心指标。 (我责怪会计师。)

风险

  • 任何详细程度的报告。如果需要该细节,通常意味着每一行都与决策相关。事实上,如果你不能在没有阻止的情况下拉出一个小的子集,可能是因为它当前正在被编辑。

  • 历史数据。它很少有实际的区别,但是用户理解不断变化的数据并不完美,他们对静态数据的感受并不相同。脏读不会在这里受到伤害,但偶尔会有双读。看来你不应该对静态数据设置阻塞,为什么要冒风险呢?

  • 几乎任何能够提供具有写入功能的应用程序的东西。

即使OK情景也不行。

  • 是否有任何应用程序或更新流程使用大型单笔交易?删除然后重新插入您报告的大量记录?在这种情况下,您实际上无法在这些表上使用NOLOCK

答案 5 :(得分:5)

关于报告,我们在所有报告查询中使用它来防止查询阻塞数据库。我们可以做到这一点,因为我们正在提取历史数据,而不是高达微秒的数据。

答案 6 :(得分:1)

这将为您提供脏读,并向您显示尚未提交的事务。这是最明显的答案。我不认为使用它只是为了加快你的阅读速度是个好主意。如果您使用良好的数据库设计,还有其他方法可以做到这一点。

有趣的是,注意到没有发生什么。 READ UNCOMMITTED不仅忽略其他表锁。它也没有引起任何锁定。

考虑生成大型报告,或者使用大型且可能复杂的SELECT语句将数据迁移出数据库。这将导致共享锁定在您的事务期间可能会升级为共享表锁定。其他事务可以从表中读取,但更新是不可能的。如果它是一个生产数据库,这可能是一个坏主意,因为生产可能会完全停止。

如果您使用READ UNCOMMITTED,则不会在表上设置共享锁。您可能会从某些新事务中获得结果,或者您可能不会依赖于数据插入表的位置以及SELECT事务已读取的时间。如果发生页面拆分(数据将被复制到数据文件中的另一个位置),您也可能会获得相同的数据两次。

因此,如果您在执行SELECT时可以插入数据非常重要,那么READ UNCOMMITTED可能有意义。您必须考虑您的报告可能包含一些错误,但如果它基于数百万行而且只有少数几个在更新时会更新,这可能是“足够好”。您的交易也可能一起失败,因为可能无法保证行的唯一性。

更好的方法可能是使用SNAPSHOT ISOLATION LEVEL但您的应用程序可能需要进行一些调整才能使用它。这方面的一个示例是,如果您的应用程序对行进行独占锁定,以防止其他人读取它并进入UI中的编辑模式。 SNAPSHOT ISOLATION LEVEL也会带来相当大的性能损失(特别是在磁盘上)。但是你可以通过在问题上抛出硬件来克服这个问题。 :)

您还可以考虑恢复数据库的备份,以用于报告数据或将数据加载到数据仓库中。

答案 7 :(得分:1)

在源极不可能改变的情况下使用READ_UNCOMMITTED。

  • 阅读历史数据时。例如两天前发生的一些部署日志。
  • 再次阅读元数据时。例如基于元数据的应用程序。

如果您知道在获取操作期间源可能会发生变化,请不要使用READ_UNCOMMITTED。

答案 8 :(得分:-1)

它可以用于一个简单的表,例如在仅插入审计表中,其中没有对现有行的更新,并且没有fk到其他表。插入是一个简单的插入,没有或几乎没有回滚的机会。

答案 9 :(得分:-6)

我现在总是使用READ UNCOMMITTED。问题最少,速度很快。使用其他隔离时,您几乎总会遇到一些阻塞问题。

只要您使用自动增量字段并多花一点注意插入就可以了,您可以告别阻塞问题。

您可以使用READ UNCOMMITED创建错误,但说实话,确保您的插入是完整的证明是非常容易的。使用select的结果的插入/更新只是您需要注意的事项。 (在这里使用READ COMMITTED,或确保脏读不会导致问题)

所以去Dirty Reads(特别是大报告),你的软件会运行得更顺畅......