首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在这种情况下,READ UNCOMMITTED / NOLOCK是否安全?

在这种情况下,READ UNCOMMITTED / NOLOCK是否安全?
EN

Stack Overflow用户
提问于 2010-06-09 05:43:05
回答 2查看 1.5K关注 0票数 2

我知道快照隔离可以解决这个问题,但我想知道NOLOCK在这种特定情况下是否安全,这样我就可以避免开销。

我有一个表,看起来像这样:

代码语言:javascript
复制
drop table Data

create table Data
(
    Id BIGINT NOT NULL,
    Date BIGINT NOT NULL,
    Value BIGINT,
    constraint Cx primary key (Date, Id)
)

create nonclustered index Ix on Data (Id, Date)

该表没有任何更新,永远不会。删除操作可能会发生,但它们永远不应与SELECT冲突,因为它们会影响表的另一端,也就是较老的一端。插入是常规的,对(Id,Date)索引的页面拆分是非常常见的。

我在标准INSERT和SELECT之间遇到了死锁情况,如下所示:

代码语言:javascript
复制
select top 1 Date, Value from Data where Id = @p0 order by Date desc

因为INSERT获取的是Cx (Date,Id;Value)上的锁,然后是Ix (Id,Date),而SELECT获取的是Ix (Id,Date)上的锁,然后是Cx (Date,Id;Value)。这是因为SELECT首先在Ix上查找,然后加入到Cx上的查找。

交换聚集索引和非聚集索引将打破此循环,但这不是一个可接受的解决方案,因为它将引入具有其他(更复杂)SELECT的循环。

如果我将NOLOCK添加到SELECT,在这种情况下会出错吗?它可以返回:

多行,即使我要求前1行?

没有行,即使存在行并且已经提交?

最糟糕的是,行不满足WHERE子句?

我在网上读了很多关于这方面的文章,但我所见过的计数过多或计数不足的异常情况的唯一复制品(

一个

两个

)涉及扫描。这只涉及到寻道。杰夫·阿特伍德

有一篇文章

关于使用NOLOCK的讨论引起了很好的讨论。我特别感兴趣的是Rick Townsend的评论:

其次,如果您读取脏数据,那么您将面临读取完全错误的行的风险。例如,如果您的select读取一个索引来查找您的行,那么update将更改行的位置(例如:由于页面拆分或对聚集索引的更新),当您的select读取实际数据行时,它要么不再存在,要么完全不同的行!

是否可以只使用插入,而不使用更新?如果是这样的话,我想即使是我在一个只插入的表上的查找也可能是危险的。

更新:

我在试着弄清楚

快照隔离的工作原理

(

https://docs.microsoft.com/en-us/previous-versions/sql/sql-server-2005/administrator/ms345124(v=sql.90%29)

..。它似乎是基于行的,事务读取表(没有共享锁!),找到它们感兴趣的行,然后查看是否需要从tempdb中的版本存储中获取该行的旧版本。

但在我的例子中,所有行都不会有一个以上的版本,所以版本存储看起来相当没有意义。如果找到没有共享锁的行,与只使用NOLOCK有什么不同?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2010-06-09 06:14:41

使用NOLOCK或READ UNCOMMITTED意味着您放弃了任何一致性保证。句号。

如果你需要一致性,不要做脏读。您的整个解释依赖于未记录的行为,在未来的版本中可能会发生更改,更糟糕的是,在

特定的访问计划

正如您对查询所期望的那样。查询优化器可以自由选择它认为合适的任何计划,并且您所做的任何假设都可能在生产中被打破。所以回到原点:如果你没有准备好面对后果,就不要做肮脏的阅读。

不确定这是否适用,也不清楚您试图通过查询/表实现什么,但也许这篇文章可能会有所帮助:

将表用作队列

..。

更新

其中NOLOCK读取将读取不一致的状态(例如,读取过时的非聚集索引键并将其追逐到聚集索引中缺少的行),快照读取将在版本存储中找到“缺少的”行。对于稳定的数据,快照读取与nolock读取相同。每当数据发生变化(未提交的更新)时,版本存储的魔力就开始发挥作用,因为快照读取进入版本存储并找到‘旧’值(稳定和一致),其中nolock读取将变得混乱,并将指针追逐到lala land。

票数 7
EN

Stack Overflow用户

发布于 2010-06-09 05:56:31

在这种情况下,使用NOLOCK应该是安全的。另一个想法是:在Ix索引上添加一个包含列的值应该可以消除在Cx上的查找。

代码语言:javascript
复制
create nonclustered index Ix on Data (Id, Date) include (Value)
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/3001531

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档