PostgreSQL 隔离级别的行为

Posted

技术标签:

【中文标题】PostgreSQL 隔离级别的行为【英文标题】:Behavior of PostgreSQL isolation levels 【发布时间】:2018-11-16 10:26:03 【问题描述】:

我正在阅读PostgreSQL Manual的第13.2节,但发现那里的文字描述不够清晰,缺乏示例。

例如以下两段不清楚谁在学习PostgreSQL:

带有 ON CONFLICT DO UPDATE 子句的 INSERT 行为类似。在读 提交模式,建议插入的每一行都将插入或更新。 除非存在不相关的错误,否则可以保证这两种结果之一。如果 冲突源于另一笔交易,其影响尚不可见 对于 INSERT,UPDATE 子句将影响该行,即使可能 该行的任何版本通常对命令是不可见的。"

Repeatable Read 模式提供了严格的保证每个事务 看到一个完全稳定的数据库视图。但是,这种观点不一定总是与同一级别的并发事务的某些串行(一次一个)执行一致。例如,即使是此级别的只读事务,也可能会看到更新的控制记录以显示批次已完成,但看不到在逻辑上属于批次的详细记录之一,因为它读取了控制记录的较早版本.

有人可以举例说明这两段的内容吗?

有谁知道我在哪里可以找到关于 PostgreSQL 隔离级别行为的正式描述?我正在寻找这个,因为它是一个高级主题,我相信正式的描述将有助于阐明它是如何工作的,从而有助于避免事务之间的并发错误。

更新:我的另一个疑问是,当可序列化事务可以与其他隔离级别的其他事务同时运行时,如何处理数据库机制决定提交或中止它的方式?数据库是否决定可序列化事务的结果,就好像其他事务也使用可序列化隔离运行一样?

谢谢

更新 2:到目前为止,我发现的关于隔离级别的实现细节最好的是 PostgreSQL Wiki Serializable Page。

【问题讨论】:

我想知道为什么有两个建议可以结束这个问题。一个潜在的回应似乎对于清楚地理解这个如此重要的数据库编程主题非常有用。 我认为这个问题有两个问题:首先,异地链接形式的答案很可能在将来的某个时候中断;其次,尚不清楚答案中究竟需要哪些额外的细节——您发现不清楚的描述具体是什么,以及“正式描述”有何不同? 请注意,我所说的“问题”并不是说它没有有用,而是它不太适合本网站。如果您edit 将问题集中在两段之一(您可以随时针对另一段提出单独的问题),并解释您已经理解的部分,则请求解释和示例可能更适合这种格式. @IMSoP 我根据您的 cmets 调整了我的问题,现在它更侧重于我希望更好地解释的示例,最好是附带 SQL。正式描述的请求现在被降为第二优先级,尽管我相信除了代码本身之外没有任何地方这样的描述:-(。请阅读我对“Laurenz Albe”的评论,了解我对两者的不理解段落。谢谢 我仍然对您认为“正式描述”的外观以及它如何适合本网站感到困惑。隔离级别本身在 ISO SQL 标准中是标准化的,因此那里将正式描述他们必须做出的保证。 Postgres 如何实现这些保证的确切细节,根据定义,是一个实现细节,因此它们只会根据当前代码的细节被记录 【参考方案1】:

READ COMMITTED:每条 SQL 语句都会拍摄数据库的新快照,因此每条语句都会在并发事务提交后立即看到它们所做的更改。不会出现序列化错误。

REPEATABLE READ:事务中的第一条语句获取整个事务中保留的数据库快照,因此所有语句都看到数据库的相同状态。如果您在拍摄快照后尝试修改已被并发事务修改的行,则可能会发生序列化错误。这个隔离级别并不比READ COMMITTED 贵。

SERIALIZABLE:任何可能导致结果与事务的某些串行执行顺序不一致的事务都将因序列化错误而中止。可能存在误报。这种隔离级别比其他级别更昂贵。

具体问题的答案:

INSERT ... ON CONFLICT 处于读提交隔离状态:

如果事务 1 已插入一行,但尚未提交,则运行 INSERT ... ON CONFLICT 的事务 2 将等到事务 1 已提交或回滚,然后根据需要更新或插入。不会发生约束冲突。

批处理作业和REPEATABLE READ

这一段是黑暗的;忽略它。它试图说明两个并发的可重复读取翻译可以产生与任何串行执行不一致的结果。

一个更好的例子可能是两个并发事务,它们都读取相同的数据并根据读取结果对它们执行更新。这些事务中的每一个都看不到另一个事务的修改。

查看“可序列化”下的 PostgreSQL Wiki 以获得更详细的示例。

更新问题:

这个问题我不是很清楚。

可序列化事务采用特殊的“SI”锁,可跟踪读写访问并在提交后继续存在。它们不会阻止其他会话,而是用于确定是否存在可能冲突。仅当所有个并发事务使用可序列化隔离级别时,可序列化隔离级别才能正常工作。

【讨论】:

不错的简历(不能再短了)。但是你能举出上面两段描述的例子吗?第一段:什么是可能的“不相关的错误”?什么例子与“如果冲突源于......”的情况相匹配?第 2 段:您能否澄清“......即使是这个级别的只读事务也可能看到......”中的示例,在这种情况下,我看不到语句的其余部分是如何描述的“但看不到其中一个...“ 可以发生?如果您可以为您的示例提供 SQL,那将非常清楚。谢谢 我在原始问题的末尾附加了另一个问题(UPDATE 段落)。谢谢 好的,解释清楚了。有趣的是你的最后一句话“只有当所有并发事务都使用可序列化隔离级别时,可序列化隔离级别才能正常工作。”但如果他们不这样做,处理混合隔离级别的结果是什么?或者我们必须为应用程序的所有事务只选择一个隔离级别,这似乎非常严格?这是我在附加更新段落中的问题。 我的回答是肯定的,你必须对所有事务使用可序列化。 但这会影响应用程序的吞吐量,这就是大家所说的......如果有什么地方可以解释不同隔离级别的事务如何交互,那么理解内部并发控制会容易得多PostgreSQL的机制,因此为每个事务选择最宽松的隔离,从而实现更大的吞吐量。【参考方案2】:

关于UPDATE

中的问题

数据库是否决定可序列化事务的结果,就好像其他事务也使用可序列化隔离运行一样?"

答案是否定的。

仅在可序列化隔离级别的并发事务之间验证可序列化性。例如,假设两个事务 T1 和 T2 像这样交错:

T1: begin
T1: set transaction isolation level read committed;
T1: update addresses set street = 'Sun street' where id = 1
T2: begin
T2: set transaction isolation level serializable;
T2: select street from addresses where id = 1
T2: update addresses set street = 'Sea street' where id = 2
T1: select street from addresses where id = 2
T1: commit
T2: commit

T1 和 T2 都会提交。但是,如果将 T1 设置为可序列化隔离,则 T2 将中止。

【讨论】:

以上是关于PostgreSQL 隔离级别的行为的主要内容,如果未能解决你的问题,请参考以下文章

PostgreSQL事务隔离级别

不支持 postgresql 事务隔离级别 4

使用Django和PostgreSQL进行事务(@atomic)的默认隔离级别

PostgreSQL串行化隔离级别(SSI)的能力与实现

丢失更新会发生在 PostgreSQL 的读提交隔离级别吗?

数据库隔离级别以及传播行为