它的经常性问题 _ 下可能并发写入负载,涉及(但不同于)UPSERT
(这是 INSERT
或UPDATE
_)。
使用新的UPSERT实施INSERT ... ON CONFLICT .. DO UPDATE
,我们可以大大简化。PL / pgsql函数到INSERT
或SELECT
一个 _ _ 行(标记):
CREATE OR REPLACE FUNCTION f_tag_id(_tag text, OUT _tag_id int) AS
$func$
BEGIN
SELECT tag_id -- only if row existed before
FROM tag
WHERE tag = _tag
INTO _tag_id;
IF NOT FOUND THEN
INSERT INTO tag AS t (tag)
VALUES (_tag)
ON CONFLICT (tag) DO NOTHING
RETURNING t.tag_id
INTO _tag_id;
END IF;
END
$func$ LANGUAGE plpgsql;
比赛条件仍然有一个很小的窗口。为了 _ _ 您获得ID,请执行以下操作:
CREATE OR REPLACE FUNCTION f_tag_id(_tag text, OUT _tag_id int) AS
$func$
BEGIN
LOOP
SELECT tag_id
FROM tag
WHERE tag = _tag
INTO _tag_id;
EXIT WHEN FOUND;
INSERT INTO tag AS t (tag)
VALUES (_tag)
ON CONFLICT (tag) DO NOTHING
RETURNING t.tag_id
INTO _tag_id;
EXIT WHEN FOUND;
END LOOP;
END
$func$ LANGUAGE plpgsql;
这一直循环直到成功INSERT
或失败为止SELECT
。称呼:
SELECT f_tag_id('possibly_new_tag');
如果 同一事务中的 后续命令依赖于该行的存在,并且实际上其他事务可能同时更新或删除该行,则可以使用来锁定SELECT
语句中的现有行FOR SHARE
。 如果改为插入该行,则该行将一直锁定到事务结束为止。
如果大多数时间都插入了新行,则从开始开始INSERT
使其更快。