我在PostgreSQL 9.3上。我是唯一一个在数据库上工作的人,我的代码按顺序运行查询以进行单元测试。
大多数情况下,以下UPDATE查询运行没有问题,但有时它会在PostgreSQL服务器上进行锁定。然后查询似乎永远不会结束,而通常只需要3秒。 我必须确切地说,查询在单元测试上下文中运行,即数据完全相同,而锁定是否发生。代码是唯一更新数据的过程。
我知道在对自更新表使用更新查询时,PostgreSQL可能存在锁定问题。当使用LEFT JOIN时,大部分结束。
我也知道LEFT JOIN查询可以用UPDATE的NOT EXISTS查询替换,但在我的情况下,LEFT JOIN要快得多,因为要更新的数据很少,而NOT EXISTS应该访问所有行候选
所以我的问题是:我应该使用什么PostgreSQL命令(如表上的Explicit Locking 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
)
答案 0 :(得分:0)
我认为您的查询已被其他查询锁定。您可以通过
找到此查询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/
也可以使用ACCESS EXCLUSIVE LOCK来阻止任何查询读写表t_territories
LOCK t_territories IN ACCESS EXCLUSIVE MODE;
有关此处https://www.postgresql.org/docs/9.1/static/explicit-locking.html
的更多信息