首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >选择要更新的postgres中的锁定顺序

问选择要更新的postgres中的锁定顺序
EN

Stack Overflow用户
提问于 2015-03-13 20:24:56
回答 1查看 1.9K关注 0票数 8

假设表a和b都有一行,则查询

代码语言:javascript
复制
 SELECT * FROM a, b FOR UPDATE

应该有两个行级锁(一个在a上,一个在b上)。是否有任何已定义的顺序来获取锁?是否有任何方法要求表b中的锁在a之前获得锁(以避免与其他事务发生死锁)?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2015-03-16 03:26:00

是否有任何已定义的顺序来获取锁?

据我所知,对SELECT *来说并不是。由于在这种情况下没有记录任何锁排序,所以即使在实际中它存在,也不能依赖它。它可能会在将来的版本中改变。

是否有任何方法要求表b中的锁在a之前获得锁(以避免与其他事务发生死锁)?

如果必须使用SELECT *,则不使用。但是如果你能控制SELECT-list,是的。看起来,行锁是按照相关元组字段在SELECT列表中出现的顺序获得的,因此:

代码语言:javascript
复制
SELECT a.x, b.x FROM b, a FOR UPDATE;

将从a获取行的锁,然后从b获取行的锁。无论如何,目前,我认为标准没有指定这一点,也没有在文档中看到对它的任何引用,所以以后可能会发生变化。

个人..。我会使用DO块或单独的查询。也许可以通过一些子查询或CTE来实现这一点,但是您必须在它们之间创建某种形式的人工依赖,以确保排序。很脆弱也不值得。

让我们看看实际发生了什么:

代码语言:javascript
复制
regress=> EXPLAIN (VERBOSE) SELECT * FROM a, b FOR UPDATE;
                                  QUERY PLAN                                   
-------------------------------------------------------------------------------
 LockRows  (cost=0.00..129674.00 rows=5760000 width=20)
   Output: a.x, b.x, a.ctid, b.ctid
   ->  Nested Loop  (cost=0.00..72074.00 rows=5760000 width=20)
         Output: a.x, b.x, a.ctid, b.ctid
         ->  Seq Scan on public.a  (cost=0.00..34.00 rows=2400 width=10)
               Output: a.x, a.ctid
         ->  Materialize  (cost=0.00..46.00 rows=2400 width=10)
               Output: b.x, b.ctid
               ->  Seq Scan on public.b  (cost=0.00..34.00 rows=2400 width=10)
                     Output: b.x, b.ctid
(10 rows)

执行查询,然后将结果输入到LockRows节点。LockRows是做什么的?要做到这一点,是时候开始编写源代码了。

src/backend/executor/nodeLockRows.c是相关代码。这里有很多,但它的要点是,它按顺序对RowMark的列表进行迭代,并按顺序获取每个锁。列表由ExecInitLockRows设置,它复制和过滤在计划期间准备并存储在LockRows节点中的列表。

我没有时间在计划器中追溯以找到LockRows创建的顺序,但是IIRC基本上只是解析顺序(对于SELECT *)或字段在SELECT列表中出现的顺序(如果您不使用*)。我建议不要依赖它。

票数 9
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/29041327

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档