假设我的数据库中有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.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();
所以问题是关于函数folderfile_fill_pathkey()
的波动性。文件说
任何带副作用的功能必须标记为VOLATILE
但据我所知 - 此函数不会更改它所依赖的表中的任何数据,因此我可以将此函数标记为IMMUTABLE
。这是正确的吗?
如果我在同一事务中将许多行批量插入FOLDERFILE
,那么IMMUTABLE触发器功能是否会出现任何问题,例如:
BEGIN;
INSERT INTO FOLDERFILE ( ... );
...
INSERT INTO FOLDERFILE ( ... );
COMMIT;
答案 0 :(得分:5)
首先,正如@pozs已经指出的那样,您提供的函数定义绝对是STABLE
而不是IMMUTABLE
,因为它执行数据库查找。这意味着结果不是简单地从输入参数(如IMMUTABLE
建议的那样)得出的,而且也来自存储在FOLDER
表中的数据(必然会发生变化)。根据文件:
STABLE
表示该函数无法修改数据库,并且 在单个表扫描中,它将始终返回相同的内容 结果是相同的参数值,但其结果可能会改变 跨SQL语句。 这是适当的功能选择 其结果取决于数据库查找,参数变量(例如 当前时区)等。
其次,将稳定性修饰符(IMMUTABLE
/ STABLE
/ VOLATILE
)添加到触发器函数中充其量只是为了说明目的,因为AFAIK PostgreSQL实际上并没有执行任何规划这将保证他们的使用。来自pgsql-hackers
邮件列表的following post似乎支持我的声明:
无论如何,波动率对于触发函数来说都是完全无操作的 其他计划者参数,如成本/行,因为没有 计划涉及触发调用。
总结一下:你现在最好避开触发器(!)程序中的稳定性关键字,因为包含它们似乎几乎没有任何好处,但需要几个意外的警告/陷阱(见最后) @ pozs的第一个评论)。