【发布时间】: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