为什么使用READ UNCOMMITTED隔离级别?
用简单的英语,使用的缺点和优点是什么
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
在查询.NET应用程序和报告服务应用程序?
这个隔离级别允许脏读。 一个事务可能会看到一些其他事务所做的未提交的更改。
为了保持最高的隔离级别,DBMS通常会获取对数据的locking,这可能会导致并发性的丢失和较高的locking开销。 这个隔离级别放宽了这个属性。
你可能想看看关于READ UNCOMMITTED
的维基百科文章几个例子和进一步阅读。
您可能也有兴趣查看杰夫·阿特伍德的博客文章 ,了解他和他的团队如何在堆栈溢出的早期解决死锁问题。 据杰夫说:
但是
nolock
危险吗? 你可能最终读取无效的数据read uncommitted
? 是的,在理论上。 你会发现不乏数据库架构的宇航员开始在你身上丢弃ACID科学,当你告诉他们你想尝试nolock
时候,除了拉大楼火警nolock
。 这是真的:理论是可怕的。 但是我的想法是这样的:理论上讲,理论和实践没有区别,实际上是存在的。我永远不会推荐使用
nolock
作为一般的“对于你有什么nolock
”的蛇油修复任何数据库死锁问题,你可能有。 您应该首先尝试诊断问题的根源。但是在实践中,将
nolock
添加到您完全知道的查询很简单,直接的只读事务似乎从不会导致问题… 只要您知道自己在做什么。
READ UNCOMMITTED
级别的一个替代方法是您可能要考虑的是READ COMMITTED SNAPSHOT
。 再次引用杰夫:
快照依赖于全新的数据更改跟踪方法,不仅仅是一个小小的逻辑改变,它需要服务器以不同的方式处理数据。 一旦启用了这种新的数据更改跟踪方法,它将创build每个数据更改的副本或快照。 通过在竞争时读取这些快照而不是实时数据,在读取时不再需要共享锁,并且整体数据库性能可能会增加。
这可以用来查看长插入查询的进度,做出任何粗略的估计(如COUNT(*)
或粗略SUM(*)
)等。
换句话说,只要你把它们看作是估计值,并且不根据它们作出任何关键的决定,那么脏读取查询返回的结果就没有问题。
我最喜欢用于read uncommited
使用的用例是debugging事务内发生的事情。
在debugging器下启动您的软件,当您逐步完成代码行时,它会打开一个事务并修改您的数据库。 在代码停止的时候,你可以打开一个查询分析器,在读取的未被阻止的隔离级别上设置查询,看看发生了什么。
您也可以使用它来查看长时间运行的程序是否卡住或正确更新您的数据库。
如果你的公司喜欢制作过于复杂的存储过程,这是非常好的。
优点是在某些情况下可以更快。 缺点是结果可能是错误的(尚未提交的数据可能被返回),并且不能保证结果是可重复的。
如果你关心准确性,不要使用这个。
更多信息在MSDN上 :
实现脏读或隔离级别0locking,这意味着不会发出共享锁,并且不会授予排它锁。 设置此选项时,可以读取未提交或脏数据; 数据中的值可以改变,行可以在事务结束之前出现或消失在数据集中。 此选项与在事务中的所有SELECT语句中的所有表上设置NOLOCK的效果相同。 这是四个隔离级别中限制最less的一个。
什么时候可以使用READ UNCOMMITTED
?
经验法则
好 :汇总报告总数不断变化。
危险 :几乎所有其他事情。
好消息是大部分只读报告都属于这个好的类别。
更多详情…
好的使用它:
- 几乎所有面向用户的汇总报表都是针对当前的非静态数据,例如年初至今的销售额。 它有一个误差范围(可能小于0.1%),比input误差等其他不确定因素要低得多。
这可能涵盖了MIS部门在SSRS中所做的大部分工作。 当然,例外是在它前面有$符号的东西。 许多人用更多的热情来解释金钱,而不是用于服务客户和生成资金所需的相关核心指标。 (我怪会计师)。
有风险时
-
任何报告都可以归入细节层面。 如果需要这些细节,通常意味着每一行都与决策有关。 事实上,如果你不能阻止一个小子集,可能是因为它正在被编辑。
-
历史数据。 它很less有实际的区别,但是用户了解不断变化的数据不可能是完美的,他们对静态数据感觉不一样。 肮脏的读取不会在这里受到伤害,但双读可能会偶尔。 看到你不应该有静态数据块,为什么冒这个险?
-
几乎所有提供了具有写入function的应用程序。
甚至当OK场景不好时。
- 是否有任何应用程序或更新过程使用大单事务? 删除然后重新插入你正在报告的很多logging? 在这种情况下,你真的不能在这些表上使用
NOLOCK
。
关于报告,我们在所有的报告查询中使用它来防止查询陷入数据库。 我们可以这样做,因为我们正在拉取历史数据,而不是最新的数据。
这会给你脏读,并显示你还没有提交的交易。 这是最明显的答案。 我不认为这是一个好主意,只是为了加快你的阅读速度。 如果你使用一个好的数据库devise,还有其他的方法。
它也有趣的注意什么没有发生。 READ UNCOMMITTED不仅忽略其他表锁。 这也不会造成任何locking。
考虑你正在生成一个大的报告,或者你正在使用一个大的,可能是复杂的SELECT语句将数据从数据库中移出。 这将导致一个共享锁,在您的交易期间可能会升级到共享表锁。 其他交易可能会从表中读取,但更新是不可能的。 如果生产数据库自生产以来可能完全停止,这可能是一个坏主意。
如果使用READ UNCOMMITTED,则不会在表上设置共享锁。 您可能会从一些新的事务中获得结果,或者您可能不会根据数据插入的表的位置以及您的SELECT事务已经读取了多长时间。 如果发生页面拆分(数据将被复制到数据文件中的另一个位置),您也可能会获得相同的数据两次。
所以,如果对于你来说非常重要的是你可以在做SELECT的时候插入数据,那么READ UNCOMMITTED可能是有道理的。 你必须考虑到你的报告可能包含一些错误,但是如果它基于数百万行并且只有less数行在select结果时被更新,这可能是“足够好”的。 由于行的唯一性可能无法保证,您的交易也可能会一起失败。
一个更好的方法可能是使用SNAPSHOT隔离级别,但是您的应用程序可能需要一些调整来使用它。 其中一个例子是,如果您的应用程序在一行上使用独占locking,以防止其他人阅读并在UI中进入编辑模式。 SNAPSHOT ISOLATION LEVEL也会带来相当大的性能损失(特别是在磁盘上)。 但是你可以通过硬件来解决这个问题。 🙂
您还可以考虑恢复数据库的备份以用于报告或将数据加载到数据仓库中。
在源极不太可能改变的情况下使用READ_UNCOMMITTED。
- 在阅读历史数据时。 例如两天前发生的一些部署日志。
- 再次阅读元数据时。 例如基于元数据的应用
当您在获取操作期间知道可能会更改时,请勿使用READ_UNCOMMITTED。
它可以用于一个简单的表格,例如在只有插入的审计表格中,其中没有更新到现有的行,没有fk到其他表格。 插入是一个简单的插入,没有或几乎没有回滚的机会。
我现在总是使用READ UNCOMMITTED。 这是最快的问题。 当使用其他隔离时,您几乎总是会遇到一些阻塞问题。
只要你使用自动递增字段,并多花点注意插入,那么你的罚款,你可以说再见阻止问题。
你可以用READ UNCOMMITED写错,但说实话,确保你的插入是完全的certificate是很容易的。 插入/更新使用select的结果只是你需要注意的事情。 (在这里使用READ COMMITTED,或者确保脏读不会导致问题)
所以去脏读(特别是大报告),您的软件将运行更顺畅…