【问题标题】:Will psycopg2 cursor.fetchmany() see concurrent committed transactions?psycopg2 cursor.fetchmany() 会看到并发提交的事务吗?
【发布时间】:2022-01-20 18:55:28
【问题描述】:

考虑以下代码:

import psycopg2

conn = psycopg2.connect(**credentials)
cur = conn.cursor()
cur.execute('select * from some_table')  # Imagine some_table to be a very big table
while True:
    rows = cur.fetchmany(1000)
    if not rows:
        break
    do_some_processing(rows)

cur.close()
conn.commit()

问题1:如果一个并发事务在循环运行时向some_table插入新行,如果事务隔离级别设置为“已提交”,是否会获取新行?

问题2:如果一个并发事务在循环运行时更新了some_table中的一些行,如果事务隔离级别设置为“已提交”,是否会获取更新的行?

根据 Postgres 文档:

Read Committed 是 PostgreSQL 中的默认隔离级别。当事务使用此隔离级别时,SELECT 查询(没有 FOR UPDATE/SHARE 子句)只看到查询开始之前提交的数据;它永远不会看到未提交的数据或并发事务在查询执行期间提交的更改。实际上,SELECT 查询会在查询开始运行的那一刻看到数据库的快照。但是,SELECT 确实会看到在其自己的事务中执行的先前更新的影响,即使它们尚未提交。另请注意,如果其他事务在第一个 SELECT 开始之后和第二个 SELECT 开始之前提交更改,两个连续的 SELECT 命令可以看到不同的数据,即使它们在一个事务中

在上面的代码中,事务中只有 1 个SELECT 查询,这意味着没有“连续的 SELECT 命令”,所以我的假设是游标不会看到任何新的插入/更新。这是正确的吗?如果是,那么游标如何始终“记住”数据库的旧状态?如果循环运行几个小时/天怎么办?这种情况会导致一些与 MVCC 相关的磁盘膨胀或类似情况吗?

【问题讨论】:

  • 如果您在您保持打开的事务中执行更新(基本上是删除/插入)或删除,则会发生膨胀。然后,如果事务执行 ROLLBACK,则服务器必须让 VACUUM 不触及旧行。对于 SELECT,服务器使用 [System columns] 此处的信息来过滤它返回的行,这样新行就不会在将来出现时被看到。看到这个帖子MVCC

标签: python postgresql psycopg2 transaction-isolation


【解决方案1】:

无论游标持续多长时间,您的游标都会看到 SELECT 语句开始时存在的任何记录。数据库服务器非常擅长将多个“代”表分开。例如,如果您使用 BEGIN TRANSACTION,那么只有在出现 COMMIT TRANSACTION 之前,您才能看到您所做的更改。

【讨论】:

    【解决方案2】:

    只要游标处于打开状态,旧版本的行就会一直保留。是的,这意味着将游标保持打开数天会有膨胀的风险,因为无法删除当前已过时且在打开游标时有效的元组。

    您可能会争辩说,这只需要应用于定义游标的表,因为以后不能将新表添加到查询中(在读取提交模式下)。但是这种推理不适用于具有动态 SQL 的函数,它可以随时引入新表。无论如何,这会使会计变得更加复杂,因此没有完成。因此,在游标关闭之前,在数据库范围内,不能删除游标时代的元组。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-10-17
      • 2016-02-13
      • 1970-01-01
      • 1970-01-01
      • 2021-08-28
      • 1970-01-01
      • 1970-01-01
      • 2011-09-05
      相关资源
      最近更新 更多