postgresql - Postgres SSI 行为

标签 postgresql transactions transaction-isolation snapshot-isolation

我试图了解 SSI 在 Postgres 中的实际行为。我的理解是,如果我有两个事务与同一个表交互,但事务不与表中的相同行交互,那么不会发生异常。

但是,我正在运行以下测试,其中事务一执行以下操作:

cur = engine.cursor()
cur.execute('SELECT SUM(value) FROM mytab WHERE class = 1')
s = cur.fetchall()[0][0]
print('retrieved sum is...')
print(s)
print('sleeping....')
time.sleep(10)
cur.execute('INSERT INTO mytab (class, value) VALUES (%s, %s)', (1, s))
engine.commit()

当上面的第一个事务正在休眠时,我运行第二个事务:

cur = engine.cursor()
cur.execute('SELECT SUM(value) FROM mytab WHERE class = 2')
s = cur.fetchall()[0][0]
print('retrieved sum is...')
print(s)
cur.execute('INSERT INTO mytab (class, value) VALUES (%s, %s)', (2, s))
engine.commit()

在这种情况下,第二个事务仅接触 class = 2 的行,而第一个事务仅接触 class = 1 的行。但这会导致第一个事务失败,并出现以下异常:

could not serialize access due to read/write dependencies among transactions
DETAIL:  Reason code: Canceled on identification as a pivot, during write.
HINT:  The transaction might succeed if retried.

供引用mytab非常简单,如下所示:

class   value
1   10
1   20
2   100
2   200

除了标准的 engine = psycopg2.connect 设置之外,我还在运行上述代码之前使用此行设置事务隔离级别:

engine.set_isolation_level(psycopg2.extensions.ISOLATION_LEVEL_SERIALIZABLE)

最佳答案

你的理解基本正确,但是SSI算法并不完美,所以总是存在一定的误报风险(例如docs中提到的,行锁可能会组合成页锁,优化以牺牲精度为代价的内存)。

此处的行为是 predicate locking implementation 的限制,即:

For a table scan, the entire relation will be locked.

基本上,在运行第一个查询 WHERE class = 1 后,需要检查其他事务的 future 插入,以确定它们是否满足此条件他们是可见的。实际上,除了最简单的条件之外,执行此检查对于所有情况都是不切实际或不可能的,因此为了谨慎起见,将对整个表进行谓词锁定。

细粒度谓词锁实现是 based on indexing ,因为根据例如关系的受影响子集进行推理要容易得多B 树范围比任意 WHERE 约束而言。

换句话说,如果您的 class 列上有索引 - 并且表中有足够的记录供规划器实际使用它 - 您应该会得到您期望的行为。

关于postgresql - Postgres SSI 行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57776922/

相关文章:

java - 为什么并发数据库连接看到彼此未提交的更改,尽管隔离设置为 "read committed"?

postgresql - 从 Dataframe 到 DB 的批量插入忽略 Pyspark 中的失败行

postgresql - 获取 PostgreSQL 登录角色的加密密码

在 Ubuntu 12.04 上安装 Postgresql 9.2

spring - 如何为自定义隔离级别配置 eclipselink jpa 方言

database - 如何锁定数据库表或一系列行以进行写入?

PostgreSQL now() 函数不返回时间

c# - .net TransactionScope 异常

mysql - 我们可以在不创建过程的情况下在 mysql 中运行代码吗

php - Zend DB 原子事务