PostgreSQL 等效于 SQLServer 的 NoLock 提示

Posted

技术标签:

【中文标题】PostgreSQL 等效于 SQLServer 的 NoLock 提示【英文标题】:PostgreSQL Equivalent of SQLServer's NoLock Hint 【发布时间】:2010-03-06 23:56:12 【问题描述】:

在 SQLServer 中,您可以使用语法“(nolock)”来确保查询不会锁定表或不会被锁定同一表的其他查询阻塞。 例如

SELECT * FROM mytable (nolock) WHERE id = blah

Postgres 中的等效语法是什么?我在 PG (http://www.postgresql.org/docs/8.1/interactive/sql-lock.html) 中找到了一些关于表锁定的文档,但这一切似乎都是针对如何锁定一个表,而不是确保它没有锁定

【问题讨论】:

等等,让我看看我是否明白这一点。有一个选项可以忽略表上的锁???如果为真,那么在验证新约束时可以选择忽略现有行,这是一个坏主意。 @Matthew Wood:总的来说,我倾向于同意。但是,忽略锁在某些情况下很有用,例如当您想要检查表的内容时进行调试,即使它处于非常大的更新过程中。最好忽略锁定,而不是等待几分钟/几小时以完成更新。 【参考方案1】:

SELECT 不会锁定 PostgreSQL 中的任何表,除非您想要锁定:

SELECT * FROM tablename FOR UPDATE;

PostgreSQL 使用MVCC 来最小化锁争用,以便在多用户环境中实现合理的性能。读者不会与作者或其他读者发生冲突。

【讨论】:

这是错误的,它相当于带有提示WITH(UPDLOCK) 的显式锁定,但问题是如何获得无锁定! @matthew-wood 的回答更相关。 @BogdanMart 这是他使用锁进行选择的示例,因为它隐式不锁定。【参考方案2】:

我做了一些研究,似乎 SQL Server 中的 NOLOCK 提示与 READ UNCOMMITTED 事务隔离级别大致相同。在 PostgreSQL 中,您可以设置READ UNCOMMITTED,但它会默默地将级别升级到READ COMMITTED。不支持READ UNCOMMITTED

事务隔离的 PostgreSQL 8.4 文档:http://www.postgresql.org/docs/8.4/static/transaction-iso.html

【讨论】:

一小段引述只是为了强调原因:PostgreSQL 只提供两个隔离级别的原因是,这是将标准隔离级别映射到多版本并发控制的唯一明智方法架构。 @dezso:+1,但在 9.1 中添加了 SERIALIZABLE,因此文档已更新为“......提供三个隔离级别......”但其他方面相同。【参考方案3】:

这是一个老问题,但我认为实际问题尚未得到解答。

SELECT 查询(不包含for update 子句)永远不会锁定任何行(或表),也不会阻止对表的并发访问。并发 DML(INSERT、UPDATE、DELETE)也不会阻塞 SELECT 语句。

简单地说:Postgres 中不需要(nolock)。 读者从不阻止作者,作者从不阻止读者

【讨论】:

是的,你需要。默认隔离级别可能与 READ COMMITTED 不同,READ UNCOMMITED 的实现可能会进一步改变 @serge: 不,你根本不需要 Postgres(或 Oracle)中的 (nolock) 提示。读者从不阻止作者,作者从不阻止读者。【参考方案4】:

nolock 或 readpast 的目的是查看记录是否被当前锁定。用户可以在更新中使用它来查看标识的记录是否已更改(行受影响);如果记录未被锁定,则 therowsaffected 将为 1;如果为o,则记录被锁定

根据该结果,用户可以使用 select for update 将其锁定以供自己使用。

【讨论】:

问题是要知道 Postgres 的 等价物 是什么,而不是 nolock 的目的。【参考方案5】:

每个 SQL 语句都是一个隐式事务。 NOLOCK 提示对应于 READ UNCOMMITTED (DIRTY READ) transaction isolation level。

BEGIN TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
SELECT COUNT(1) FROM my_table;
END;

实际上,这段代码与BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED 的作用相同,但进一步保证了预期的行为。

也避免使用 COUNT(*),除非你真的需要它

【讨论】:

Postgres 不支持未提交的读取 - 它永远不会允许脏读。此外,声称count(*)count(1) 慢的说法对于每个 DBMS 来说都是错误的。事实上,在 Postgres 中 count(1) 甚至会稍微慢一些。 count(*)count(1)what 上完全相同。您可能想阅读this 以了解有关count(1) 更快的(错误)神话的详细信息。此外,从您引用的链接中:“在 PostgreSQL 中,READ UNCOMMITTED 被视为 READ COMMITTED。” - 所以你永远不会在 Postgres 中获得 read uncommitted 但是隔离级别不会改变 Postgres 中的锁定行为。而且我不是在谈论空值。我说的是count(*)count(1) 之间的区别,它们完全没有功能上的区别。你读过blog post吗? 这不是假设。很明显,Postgres 中没有read uncommitted。并且清楚地记录了读者不会阻止其他读者。读者不会屏蔽作者,作者也不会屏蔽读者。 所以有文件证明没有 READ UNCOMITTED - 你自己说的。

以上是关于PostgreSQL 等效于 SQLServer 的 NoLock 提示的主要内容,如果未能解决你的问题,请参考以下文章

PostgreSQL plpgsql try catch 块等效

Redgate SQL Prompt等效于PostgreSQL数据库

PostgreSql中是不是有等效于sp_getapplock,sp_releaseapplock的?

MySQL MATCH() AGAINST() 等效于 SQL Server

等效于 SQL SERVER 的 MySQL LIMIT 子句

C# 等效于 SQL Server 中的 IsNull() 函数