当前位置: 首页 > 知识库问答 >
问题:

PostgreSQL:防止锁定左连接的自表更新

那鹏
2023-03-14

我在使用PostgreSQL 9.3。我是唯一一个处理数据库的人,我的代码按顺序运行单元测试的查询。

大多数情况下,以下更新查询运行正常,但有时会锁定PostgreSQL server。然后,查询似乎永远不会结束,而通常只需要3秒钟。我必须确定查询在单元测试上下文中运行,即数据完全相同,而锁是否发生。代码是唯一更新数据的进程。

我知道在对自更新表使用更新查询时,PostgreSQL可能存在锁问题。当使用左连接时,大多数情况都会发生。

我也知道LEFT JOIN查询可以替换为UPDATE的NOTEXISTS查询,但在我的例子中,LEFT JOIN要快得多,因为要更新的数据很少,而NOTEXISTS应该访问相当多的行候选。

所以我的问题是:我应该使用什么样的PostgreSQL命令(比如表上的显式锁定LOCK)或选项(比如SELECT FOR UPDATE),以确保运行查询时不会出现永无止境的锁定。

查询:

-- for each places of scenario #1 update all owners that
-- are different from scenario #0
UPDATE t_territories AS upt
SET id_owner = diff.id_owner
FROM (
    -- list of owners in the source that are different from target
    SELECT trg.id_place, src.id_owner
    FROM t_territories AS trg
    LEFT JOIN t_territories AS src
       ON  (src.id_scenario = 0)
       AND (src.id_place = trg.id_place)
    WHERE (trg.id_scenario = 1)
    AND (trg.id_owner IS DISTINCT FROM src.id_owner)
    -- FOR UPDATE -- bug SQL : FOR UPDATE cannot be applied to the nullable side of an outer join
) AS diff
WHERE (upt.id_scenario = 1)
AND (upt.id_place = diff.id_place)

表结构:

CREATE TABLE t_territories
(
  id_scenario integer NOT NULL,
  id_place integer NOT NULL,
  id_owner integer,
  CONSTRAINT t_territories_pk PRIMARY KEY (id_scenario, id_place),
  CONSTRAINT t_territories_fkey_owner FOREIGN KEY (id_owner)
      REFERENCES t_owner (id) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE RESTRICT
)

共有1个答案

锺离德运
2023-03-14

我认为您的查询已被另一个查询锁定。您可以通过以下方式找到此查询:

SELECT
  COALESCE(blockingl.relation::regclass::text,blockingl.locktype) as locked_item,
  now() - blockeda.query_start AS waiting_duration, blockeda.pid AS blocked_pid,
  blockeda.query as blocked_query, blockedl.mode as blocked_mode,
  blockinga.pid AS blocking_pid, blockinga.query as blocking_query,
  blockingl.mode as blocking_mode
FROM pg_catalog.pg_locks blockedl
JOIN pg_stat_activity blockeda ON blockedl.pid = blockeda.pid
JOIN pg_catalog.pg_locks blockingl ON(
  ( (blockingl.transactionid=blockedl.transactionid) OR
  (blockingl.relation=blockedl.relation AND blockingl.locktype=blockedl.locktype)
  ) AND blockedl.pid != blockingl.pid)
JOIN pg_stat_activity blockinga ON blockingl.pid = blockinga.pid
  AND blockinga.datid = blockeda.datid
WHERE NOT blockedl.granted
AND blockinga.datname = current_database()

我在这里找到了这个问题http://big-elephants.com/2013-09/exploring-query-locks-in-postgres/

还可以使用访问独占锁来防止任何读取和写入表的查询t\u

LOCK t_territories IN ACCESS EXCLUSIVE MODE;

有关锁的更多信息,请点击此处https://www.postgresql.org/docs/9.1/static/explicit-locking.html

 类似资料:
  • 我有一个表,需要离开外部连接两个不同的表。当我将表放入查询中两次,并将其与where子句中的self连接时(如下面的句子),它就可以工作了。我认为这不应该是正确的做法。如何编写select语句并将表与多个不同的表进行外部联接?

  • 对于我的Hi/Lo实现,我需要一个函数来获取独占表锁、更新值并选择一行。我想出了以下代码: 但是,在调用该函数时,它返回的不是一行,而是一列,内容类似于“未命名门户3”。我想我应该迭代返回的ref(但如何)? 我可以使用的另一种方法是使用UPDATE RETURNING语句,但是我不确定在这种情况下是否会出现竞争情况。任何帮助都将不胜感激。谢谢

  • 问题 你正在写一个多线程程序,其中线程需要一次获取多个锁,此时如何避免死锁问题。 解决方案 在多线程程序中,死锁问题很大一部分是由于线程同时获取多个锁造成的。举个例子:一个线程获取了第一个锁,然后在获取第二个锁的 时候发生阻塞,那么这个线程就可能阻塞其他线程的执行,从而导致整个程序假死。 解决死锁问题的一种方案是为程序中的每一个锁分配一个唯一的id,然后只允许按照升序规则来使用多个锁,这个规则使用

  • 问题内容: 希望有一些比我更聪明的DBA,可以帮助我找到所需做的很好的解决方案。 为了便于讨论,假设我有一个名为“ work”的表,其中包含一些列,其中之一是代表来自给定客户端的该行工作的所有权的列。场景是我将连接2个客户端,并轮询一个表以完成工作,当显示一行(或一定数量的行)时,选择该行的第一个客户端也将对其进行更新以暗示所有权,即更新将删除那些返回给其他任何客户选择内容的行。我的问题是,在这种

  • 本文向大家介绍怎么防止死锁?相关面试题,主要包含被问及怎么防止死锁?时的应答技巧和注意事项,需要的朋友参考一下 尽量使用 tryLock(long timeout, TimeUnit unit)的方法(ReentrantLock、ReentrantReadWriteLock),设置超时时间,超时可以退出防止死锁。 尽量使用 Java. util. concurrent 并发类代替自己手写锁。 尽量

  • 我需要按列对进行排序。但是after join(或leftJoin)值被第二个表中的值覆盖。下面是一些代码: 更改表中字段的名称(如:id->account_id和:id->role_id)将是一种解决办法,但我不是这样的情况--需要为每个表设置名为的主键。 [编辑]是的,所以问题很简单:如何解决这个问题?