PostgreSQL插入或更新触发函数易失性类别

2ca*_*can 4 postgresql volatile immutability volatility

假设我的DB(postgresql-9.x)中有2个表

CREATE TABLE FOLDER (
    KEY BIGSERIAL PRIMARY KEY,
    PATH TEXT,
    NAME TEXT
);
CREATE TABLE FOLDERFILE (
    FILEID BIGINT,
    PATH TEXT,
    PATHKEY BIGINT
);
Run Code Online (Sandbox Code Playgroud)

我自动更新FOLDERFILE.PATHKEY来自FOLDER.KEY每当我插入或更新FOLDERFILE

CREATE OR REPLACE FUNCTION folderfile_fill_pathkey() RETURNS trigger AS $$
DECLARE
  pathkey bigint;
  changed boolean;
BEGIN
  IF tg_op = 'INSERT' THEN
     changed := TRUE;
    ELSE IF old.FILEID != new.FILEID THEN
       changed := TRUE;
    END IF;
  END IF;
  IF changed THEN
     SELECT INTO pathkey key FROM FOLDER WHERE PATH = new.path;
     IF FOUND THEN
       new.pathkey = pathkey;
     ELSE
       new.pathkey = NULL;
     END IF;
  END IF;
  RETURN new;
END
$$ LANGUAGE plpgsql VOLATILE;

CREATE TRIGGER folderfile_fill_pathkey_trigger AFTER INSERT OR UPDATE 
ON FOLDERFILE FOR EACH ROW EXECUTE PROCEDURE fcliplink_fill_pathkey();
Run Code Online (Sandbox Code Playgroud)

因此,问题在于功能的folderfile_fill_pathkey()波动性。文件说

任何具有副作用的功能都必须标记为VOLATILE

但是据我了解–该函数不会更改它依赖的表中的任何数据,因此我可以将该函数标记为IMMUTABLE。正确吗?

如果我将多个行批量插入FOLDERFILE同一事务中,则IMMUTABLE触发功能是否会出现任何问题,例如:

BEGIN;
INSERT INTO FOLDERFILE ( ... );
...
INSERT INTO FOLDERFILE ( ... );
COMMIT;
Run Code Online (Sandbox Code Playgroud)

Pri*_*mre 5

首先,正如@pozs已经指出的那样,您提供的函数定义绝对是肯定的,STABLE而不是IMMUTABLE因为它执行数据库查找。这意味着结果不只是从输入参数中得出(正如IMMUTABLE所建议的那样),而且还从存储在FOLDER表中的数据中得到(必然会发生变化)。根据文档:

STABLE表示该函数无法修改数据库,并且在单个表扫描中它将针对相同的参数值一致地返回相同的结果,但其结果可能会在SQL语句之间发生变化。对于 其结果取决于数据库查找,参数变量(例如当前时区)等的函数这是适当的选择

其次,在触发器函数中添加稳定性修饰符(IMMUTABLE/ STABLE/ VOLATILE)最多只能起到说明作用,因为AFAIK PostgreSQL实际上并未执行任何保证使用它们的计划。在下面的帖子pgsql-hackers邮件列表似乎支持我的要求:

无论如何,对于触发器功能,波动率是完全不可操作的,因为成本/行等其他计划程序参数也是如此,因为触发器调用中没有计划。

综上所述:您最好暂时避免在trigger(!)过程中使用稳定性关键字,因为将它们包括在内似乎并没有带来什么好处,但会带来一些意想不到的警告/陷阱(请参阅@pozs第一个注释的结尾) )。