【问题标题】:Postgres SSI BehaviorPostgres SSI 行为
【发布时间】:2020-01-06 16:05:10
【问题描述】:

我试图了解 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)

【问题讨论】:

  • 你的意思是SERIALIZABLE隔离吗?并且您是否阅读了手册中涵盖它的部分? postgresql.org/docs/11/transaction-iso.html#XACT-SERIALIZABLE
  • 是的,我的意思是 SERIALIZABLE 隔离(我的理解是 Postgres 使用 SSI 来实现 SERIALIZABLE 隔离,如果不是这种情况,也很高兴知道)。我已经阅读了手册,这就是我得到问题中显示的mytab 示例的地方。但是,文档中的示例显示了两个更改相交集中行的事务。就我而言,我正在测试行属于两个不相交集的情况。
  • 我觉得它从某个地方看起来很熟悉。请注意,保证是在相反的方向运行的。如果系统不能证明交易是安全的,那么它保证会抛出异常。下一个问题是为什么它无法确定您的第二笔交易是安全的,恐怕我并没有立即清楚。

标签: postgresql transactions transaction-isolation snapshot-isolation


【解决方案1】:

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

这里的行为是predicate locking implementation的一个限制,即:

对于表扫描,整个关系将被锁定。

基本上,在您的第一个查询 WHERE class = 1 运行之后,需要检查来自其他事务的未来插入以查看它们是否会满足此条件(如果它们可见)。除了最简单的情况外,实际上执行此检查是不切实际或不可能的,因此为谨慎起见,改为在整个表上使用谓词锁。

细粒度的谓词锁实现是based on indexing,因为它更容易推断受影响的关系子集,例如B-tree 范围比任意WHERE 约束条件。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-09-22
    • 2011-04-11
    • 1970-01-01
    • 1970-01-01
    • 2010-10-13
    • 1970-01-01
    • 2017-01-04
    相关资源
    最近更新 更多