PostgreSQL 语句中的 KEY SHARE OF 是什么意思?

D-K*_*D-K 4 postgresql amazon-rds

给定以下 SQL,“ONLY”、“OPERATOR(pg_catalog.=)”和“FOR KEY SHARE”有什么作用?

SELECT 1 
FROM ONLY "public"."acmeinstanceinfo" x 
WHERE "widgetid" OPERATOR(pg_catalog.=) $1 
FOR KEY SHARE OF x
Run Code Online (Sandbox Code Playgroud)

我对 Microsoft SQL 服务器有相当多的经验,但对 PostgreSQL 的经验为零。对这个查询正在做什么的任何见解都会很棒。

Lau*_*lbe 6

这是在具有外键的表中插入或更新行的效果。请参阅以下示例:

CREATE TABLE a (id integer PRIMARY KEY);

CREATE TABLE b (id integer REFERENCES a);

INSERT INTO a VALUES (1);
Run Code Online (Sandbox Code Playgroud)

现在在一个会话中,启动一个事务并锁定该行a

BEGIN;

SELECT id FROM a FOR UPDATE;

 id 
????
  1
(1 row)
Run Code Online (Sandbox Code Playgroud)

然后,在另一个会话中,尝试在 中插入一行b

INSERT INTO b VALUES (1);  -- hangs!
Run Code Online (Sandbox Code Playgroud)

发生了什么?

  • SELECT ... FOR UPDATE采取了FOR UPDATE在该行锁定a

  • INSERT必须确保没有并发事务可以删除引用的行a(或修改其任何键列),以避免不一致。

    为此,它运行

    SELECT 1
    FROM ONLY "public"."a" x 
    WHERE "id" OPERATOR(pg_catalog.=) 1 
    FOR KEY SHARE OF x;
    
    Run Code Online (Sandbox Code Playgroud)

    这里ONLY确保没有其他表受到影响,如果它a是继承层次结构的一部分,并且OPERATOR(pg_catalog.=)是模式限定运算符的PostgreSQL 语法(因为运算符也受search_path,PostgreSQL 必须确保使用正确的=运算符)。

  • 由于FOR UPDATEFOR KEY SHARE锁冲突(参见文档),第二个会话被阻止。

您可以通过使用SELECT ... FOR NO KEY UPDATE代替来避免该块SELECT ... FOR UPDATE。仅当您计划更新主键或唯一键列或打算删除该行时才需要后者。