使用READ UNCOMMITTED隔离级别的最佳情况


10

众所周知,READ UNCOMMITTED是最低的隔离级别,在这种隔离级别中可能会产生脏读和幻像读之类的内容。什么时候是使用此隔离级别的最佳时间,以及出于什么原因可以使用它?

实际上,我之前已经阅读了答案,但是由于没有足够的示例,所以我无法完全理解它。

Answers:


20

从SSMS查询生产数据库时,我使用READ_UNCOMMITTED(或NOLOCK),但从应用程序代码中不常规地使用。这种做法(连同MAXDOP 1查询提示)有助于确保对数据进行分析和故障排除的临时查询不会影响生产工作负载,并且理解结果可能不正确。

可悲的是,我看到READ_UNCOMMITTED/ NOLOCK在生产代码中广泛使用了它,以避免以牺牲数据完整性为代价进行阻塞。正确的解决方案是行版本隔离级别(SNAPSHOTREAD_COMMITTED使用READ_COMMITTED_SNAPSHOT数据库选项ON)和/或注意查询和索引调整。

我最近的代码审查了一个proc,其中唯一的更改是删除,NOLOCK因为它有时返回错误的结果。删除NOLOCK是一件好事,但是,由于知道丢失或重复的行通常在大型表的分配顺序扫描期间发生,因此我建议也进行重构以使用一种UNION ALL技术来提高索引的使用效率。现在,查询将在几毫秒内运行,并获得正确的结果,这是世界上最好的。


7

我认为,在某些情况下,只要您接受后果并没有其他选择,就可以了。

对于其他选项,我会促使人们朝着对新应用程序使用读取提交快照隔离(RCSI)或对较旧应用程序使用SNAPSHOT ISOLATION(SI)的问题,在这些情况下,您无法轻松地针对RCSI的竞争条件测试整个代码库。

但是,这些可能不适合。您可能需要花费一些额外的时间来爱护和照顾tempdb,并确保没有人留下一个使版本存储(和tempdb)增长并填满磁盘的开放事务。

如果您没有DBA,或者没有人监视或管理SQL Server,那么这些选择可能很危险。更一般而言,并不是每个人都完全控制进入其服务器的代码,他们可以在其中更改连接字符串或代码以请求SI进行问题查询。

除此之外,大多数人的整个应用程序都不会遇到锁定问题。他们遇到诸如报告OLTP数据之类的问题。如果您可以接受NOLOCK / RU的权衡以换取那些未被编写者阻止的报告,那么就去吧。

只要确保您了解这意味着什么。这并不意味着您的查询没有任何锁,而是意味着它不尊重其他查询所取得的锁。

当然,如果您的问题是写程序/写程序锁定,唯一有用的选择是SI,但是开发人员需要花费大量的工作才能通过错误处理等适当地实现它。


5
并且,如果问题确实仅在于报告OLTP数据,则将其卸载到某种只读辅助文件(AG,日志传送,复制或自备卷)。
亚伦·伯特兰

3
@AaronBertrand然后他们将要监视第二台服务器;)
Erik Darling

5

恕我直言,现代系统上READ UNCOMMITTED 唯一有效的用例是在开发中的另一个会话中调试一个会话时,因此您可以看到它在做什么,例如存储的proc仍在运行。它通常不会在生产系统中使用。可能会有一些次要的性能提升,但是从长远来看,这将永远都不值得。


3

我们一直在医疗保健中使用它。

在查询中更改单个数据行的情况极为罕见,其读/写比约为10,000 / 1-其中大多数是插入而不是更新。例如,当实验室界面将患者的实验室结果写入数据库时​​,这些值将永远不会改变。

当数据确实更改时,它一次更改一行。没有人会更新整个列(DBA除外,否则它们会变得很糟)。

另一方面,我们运行了一堆查询来扫描诸如患者在72小时或更短时间内返回急诊室的事情,这绝对会打击表格。

在10年的医疗SQL中,我从未见过Rollback Transaction。我想进出不影响最终用户的体验。如果存在降低OLTP数据库速度的高风险和获得不良数据的低风险,我将采取NOLOCK。

我们应该使用它吗?也许吧,也许不是。一般而言,我不会说我从事的许多应用程序数据库都经过精心设计。它们通常充满反模式。


4
仅供参考,可以无锁读取部分写入的行。
马克斯·弗农

1
钱币!我真的需要我的老板给我买了另一台服务器,所以我可以登陆船这个东西....
詹姆斯

3
您可能会对Paul White撰写的有关READ UNCOMMITTED的漂亮博客文章感兴趣,特别是“ Reading Corrupt Data”部分:Read Uncommitted Isolation Level
Josh Darnell,

1

READ_UNCOMMITTED/NOLOCK当数据的准确性不是主要目标时,它是一个不错的选择。有时,只需要一个大概的总数即可。例如:存在用于INSERT或UPDATE表的存储过程。有时要更新或插入的记录数量很多(数千个记录)。在这些存储过程运行期间,我们可以NOLOCK定期在目标表上运行带有的简单选择查询,以查看其是否运行顺利(对于更新查询,如果您有要更新记录的状态更改列,我们可以使用该列运行group by查询NOLOCK以了解状态更改计数是否在不断变化)。


0

请注意,READ UNCOMMITTED会带来其他一致性问题,而不仅仅是脏读。根据访问方法的不同,您可能会丢失行,甚至多次读取同一行。如果您对这些细节感兴趣,请阅读Itzik Ben-Gan的文章


3
在默认的读取提交级别,也可能多次丢失行和读取行。如果索引键列在扫描过程中被更新并移动。
马丁·史密斯

有关此答案的侧面讨论已移至聊天室
保罗怀特9
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.