EXISTS 查询仍会锁定表吗?

发布于 2024-08-02 09:04:57 字数 159 浏览 4 评论 0原文

IF NOT EXISTS(SELECT * FROM MyTable WITH(nolock) WHERE Key = 'MyKey')
  INSERT MyTable(Key) Values('MyKey')

如果表中不存在该值,查询是否需要锁?

IF NOT EXISTS(SELECT * FROM MyTable WITH(nolock) WHERE Key = 'MyKey')
  INSERT MyTable(Key) Values('MyKey')

If The value does not exist in the table, does the query aquire a lock?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

秋千易 2024-08-09 09:04:57

来自文档

READUNCOMMITTED 和 NOLOCK 提示仅适用于数据锁。所有查询(包括具有 READUNCOMMITTED 和 NOLOCK 提示的查询)都会在编译和执行期间获取 Sch-S(架构稳定性)锁。因此,当并发​​事务持有表上的 Sch-M(架构修改)锁时,查询将被阻塞。例如,数据定义语言(DDL)操作在修改表的模式信息之前获取Sch-M锁。当尝试获取 Sch-S 锁时,任何并发查询(包括使用 READUNCOMMITTED 或 NOLOCK 提示运行的查询)都会被阻止。相反,持有 Sch-S 锁的查询会阻止尝试获取 Sch-M 锁的并发事务。有关锁定行为的详细信息,请参阅锁定兼容性(数据库引擎)。

因此它不会获取数据锁,但仍会获取架构稳定性锁。

From the docs:

READUNCOMMITTED and NOLOCK hints apply only to data locks. All queries, including those with READUNCOMMITTED and NOLOCK hints, acquire Sch-S (schema stability) locks during compilation and execution. Because of this, queries are blocked when a concurrent transaction holds a Sch-M (schema modification) lock on the table. For example, a data definition language (DDL) operation acquires a Sch-M lock before it modifies the schema information of the table. Any concurrent queries, including those running with READUNCOMMITTED or NOLOCK hints, are blocked when attempting to acquire a Sch-S lock. Conversely, a query holding a Sch-S lock blocks a concurrent transaction that attempts to acquire a Sch-M lock. For more information about lock behavior, see Lock Compatibility (Database Engine).

So it won't acquire a data lock, but it will still acquire a schema stability lock.

梦中的蝴蝶 2024-08-09 09:04:57

EXISTS 通常仍会获取锁。但你添加了一个提示,告诉它不要这样做,所以它不会。

EXISTS normally will still acquire a lock. But you added a hint that told it not to, and so it won't.

风月客 2024-08-09 09:04:57

使用 NOLOCK 提示确实可以防止行锁。但请注意,这种“查找和插入”充满了问题。该操作不是原子操作,当两个会话都发现密钥丢失并都尝试插入时,尝试执行此操作的两个会话将导致竞争条件,从而导致其中一个会话导致重复密钥冲突。它是否也是次优的,因为索引查找发生两次(一次查找键,一次定位插入位置)。最佳且正确的解决方案是实际尝试插入重复键错误并从该错误中恢复(如果已存在)。

Using a NOLOCK hint will indeed prevent the row lock. Just a heads up though, this kind of 'lookup and insert' is riddled with problems. The operation is not atomic and two sessions trying to do it will cause a race condition when both find the key missing and both try to insert, resulting in one of them causing a duplicate key violation. Is it also suboptimal because the index seek occurs twice (once to lookup the key, once to locate the insert position). The optimal and correct solution is to actually try to insert and recover from the duplicate key error if already exists.

对风讲故事 2024-08-09 09:04:57

该代码很容易出错。相反,您可以尝试:

在表上放置一个唯一索引,以便不可能插入多个冲突的行,然后直接插入。冲突会产生错误,您需要处理该错误。

或者,如果冲突是预期条件而不是异常,那么您需要使插入/检查原子化:

insert MyTable( [Key] ) 
  select 'MyKey' 
  where not exists ( 
    select * 
    from MyTable 
    where [Key] = 'MyKey' 
)

另外,请注意,(nolock) 和 Read Uncommissed 根据设计不会产生准确的结果。对于报告等来说是可以的,但是根据使用(nolock)的决策对数据采取行动是危险的。

That code is vulnerable to error. Instead you could try:

Put a unique index on the table so that it's not possible to insert multiple rows that conflict, and then just insert. A conflict generates an error, which you'd need to handle.

Or, if conflicts are an expected condition and not the exception, then you'll want to make the insert/check atomic:

insert MyTable( [Key] ) 
  select 'MyKey' 
  where not exists ( 
    select * 
    from MyTable 
    where [Key] = 'MyKey' 
)

Also, note that (nolock) and Read Uncommitted do not produce accurate results, by design. It's OK for reporting and such, but dangerous to act on your data based on a decision that uses (nolock).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文