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

Kip*_*eal 215 t-sql sql-server isolation-level

用简单的英语,使用的缺点和优点是什么

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
Run Code Online (Sandbox Code Playgroud)

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

Dan*_*llo 196

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

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

您可以查看维基百科的文章,READ UNCOMMITTED了解一些示例并进一步阅读.


您可能还有兴趣查看Jeff Atwood的博客文章,了解他和他的团队如何解决Stack Overflow早期的死锁问题.据杰夫说:

但是nolock危险吗?你最终可以用read uncommittedon 读取无效数据吗?是的,从理论上讲.你会发现不缺少数据库架构的宇航员,他们开始放弃你的ACID科学,除了你告诉他们你想尝试的时候,他们会拉出建筑物火警nolock.这是真的:理论是可怕的.但这就是我的想法:"从理论上讲,理论与实践之间没有区别.在实践中也存在差异."

我永远不会建议你使用nolock 蛇油来解决任何数据库死锁问题.您应该首先尝试诊断问题的根源.

但实际上,添加nolock到你绝对知道的查询是简单的,直截了当的只读事务似乎永远不会导致问题... 只要你知道你在做什么.

READ UNCOMMITTED您可能想要考虑的级别的一个替代方案是READ COMMITTED SNAPSHOT.再次引用杰夫:

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

  • 作者似乎暗示read uncommitted/no lock将返回上次提交的任何数据.我的理解是读取未提交将返回上次设置的任何值,即使是未提交的事务.如果是这样,结果将不是"几秒钟过时"检索数据.它(或者至少可以在写入您读取的数据的事务被回滚的情况下)检索不存在或从未提交的数据.我错了吗? (13认同)
  • [`READ UNCOMMITTED`也可能导致您读取行两次,或者错过整行](http://blogs.msdn.com/b/sqlcat/archive/2007/02/01/previously-committed-rows-might-不容错过 - 如果-NOLOCK-提示的是,used.aspx).如果在您阅读时发生了页面拆分,那么您可能会错过整个数据块.只有在结果的准确性不重要时才应使用`WITH(NOLOCK)` (13认同)
  • @DanielNolan,推荐那篇文章很危险,因为[杰夫不知道](http://samsaffron.com/archive/2008/08/27/Deadlocked+)[他在做什么](http://goo.gl/ ACo07C).Read-uncommmited只对读取数据有意义,永远不会被修改.尝试使用它来读取将被写入的表意味着您将在实践中**读取回滚的内容.这不只是你正在阅读几秒钟的数据,而是你.................................. ................... ........................... .... (7认同)
  • ...................................正在读取**从未**甚至承诺的数据.这就是腐败读取的定义.如果你打算根据那些未提交读取的结果**进行写入,那么你实际上将**写入损坏的数据.该文章还指出,"在网络应用程序中长大的MySQL,比SQL Server的开箱即用的悲观程度要低得多".不是这样,默认情况下,Sql Server在读取提交级别工作,而默认情况下MySQL工作在可重复读取,[五级](http://www.infoq.com/articles/eight-isolation-levels)远离读取-uncommitted. (5认同)
  • 很好的答案.顺便说一句,自从我知道它以来,Oracle默认拥有"快照",可能是在Sql Server引入之前的几十年.从SQL Server开始时我感到非常失望,我发现使用"原始"锁定机制解决了所有并发问题.从未在Oracle中看到"Read uncommitted".从业者和宇航员一样快乐. (4认同)
  • @ xr280xr我不认为这是杰夫所暗示的.也许你在他的文章的后半部分形成了这种印象,他提到了在数据库级别应用的"读取提交的快照模式",例如ALTER DATABASE myDatabase SET READ_COMMITTED_SNAPSHOT ON.此模式会影响"SET TRANSACTION ISOLATION LEVEL READ COMMITTED"语句的行为:它不是被其他人的事务阻止的读取,而是从事务开始时获取的数据的快照中读取. (3认同)
  • @ xr280xr这是正确的,这就是为什么除了简单的只读方案之外你不应该使用read uncomitted.对于大型查询,可能会读出可能无法提交到数据库的行,对于大型查询,这样的行将出现在结果集的尾部,并且用户只能看到结果集的头部,此工件无关紧要并且您可以通过不添加/获取额外的共享锁来减少DB范围内的锁争用,在特定情况下,这些锁是不必要的. (2认同)

Qua*_*noi 35

这可能是有用的,看久插入查询的进步,使任何粗略估计(如COUNT(*)或粗糙SUM(*))等.

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


nev*_*ves 33

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

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

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

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

  • 我的公司喜欢制作过于复杂的存储过程.什么是故障排除的好主意! (5认同)

Mar*_*ers 22

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

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

有关MSDN的更多信息:

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

  • @Kip - `select`语句不必等待获取由其他事务独占锁定的资源上的共享锁. (10认同)

Ada*_*ish 12

什么时候可以使用READ UNCOMMITTED

经验法则

:大汇总报告显示不断变化的总数.

风险:几乎所有其他事情.

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

更多详情...

好的使用它:

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

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

有风险的时候

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

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

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

甚至OK方案都不行.

  • 是否有任何应用程序或更新过程使用大型单一事务?删除然后重新插入您报告的大量记录?在这种情况下,你真的无法NOLOCK在这些表上使用任何东西.


neo*_*neo 8

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

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

当您知道源在获取操作期间可能会发生变化时,请勿使用 READ_UNCOMMITTED。


Hug*_*ves 5

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