5

假设,我的数据库中有 2 个表(postgresql-9.x)

CREATE TABLE FOLDER (
    KEY BIGSERIAL PRIMARY KEY,
    PATH TEXT,
    NAME TEXT
);
CREATE TABLE FOLDERFILE (
    FILEID BIGINT,
    PATH TEXT,
    PATHKEY BIGINT
);

每当我插入或更新时FOLDERFILE.PATHKEY,我都会自动更新:FOLDER.KEYFOLDERFILE

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();

所以问题是关于函数folderfile_fill_pathkey()波动性。文件说

任何有副作用的函数都必须标记为 VOLATILE

但据我了解 - 此函数不会更改它所依赖的表中的任何数据,因此我可以将此函数标记为IMMUTABLE. 对吗?

FOLDERFILE如果我在同一个事务中批量插入许多行,那么 IMMUTABLE 触发器函数会不会有任何问题,例如:

BEGIN;
INSERT INTO FOLDERFILE ( ... );
...
INSERT INTO FOLDERFILE ( ... );
COMMIT;
4

1 回答 1

8

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

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

其次,向您的触发器函数添加稳定性修饰符 ( IMMUTABLE/ STABLE/ VOLATILE) 充其量只是一个说明性目的,因为 AFAIK PostgreSQL 实际上并没有执行任何保证使用它们的计划。邮件列表中的以下帖子pgsql-hackers似乎支持我的主张:

无论如何,波动性对于触发函数来说是完全无操作的,就像成本/行等其他规划器参数一样,因为触发器调用中不涉及规划。

总结一下:你现在最好避免在你的触发器(!)过程中使用稳定性关键字,因为包括它们似乎几乎没有任何好处,但会带来一些意想不到的警告/陷阱(见@pozs第一条评论的结尾)。

于 2015-06-18T13:39:52.810 回答