【问题标题】:PostgreSQL insert or update trigger function volatility categoryPostgreSQL 插入或更新触发函数波动类别
【发布时间】:2015-02-27 10:38:40
【问题描述】:

假设,我的数据库中有 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 时,我都会自动从FOLDER.KEY 更新FOLDERFILE.PATHKEY

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;

【问题讨论】:

  • 这个"function"(严格来说是它的主体)不是IMMUTABLE,它只是STABLE(它从你的FOLDER表中选择,可以改变随着时间的推移:您的函数不保证相同的 "parameters") 结果相同 -- 但是,它是一个触发器,而不是经典函数:函数波动只对查询优化,但只会给你带来麻烦,如果优化触发器,f.ex. STABLE - 不适合AFTER 触发器希望查询当前命令修改的行。
  • 谢谢@pozs!我实际上并没有完全理解IMMUTABLESTABLE 之间的区别,所以我现在必须在我的数据库中修复一些东西。因此,非常感谢您的评论。
  • @pozs,据我所知 - 使我的函数 STABLE 而不是 VOLATILE 不会给我任何性能优势?如果你把它作为一个答案也很好,这样我就可以接受它——否则我必须自己做。
  • 很难预测,STABLE 是否真的表现更好。查询优化取决于很多事情。 (在你的情况下——即你没有在函数内查询触发器的目标表FOLDERFILE——这无关紧要)。但是,如果您想要精确,您应该使用真实数据测试这两种变体。
  • 好的,谢谢,我稍后会做基准测试并在这里发布结果

标签: postgresql immutability volatile volatility


【解决方案1】:

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

STABLE表示该函数不能修改数据库, 在单个表扫描中,它将始终返回相同的 结果相同的参数值,但其结果可能会改变 跨 SQL 语句。 This is the appropriate selection for functions 其结果取决于数据库查找、参数变量(例如 当前时区)等。

其次,向触发器函数添加稳定性修饰符 (IMMUTABLE/STABLE/VOLATILE) 最多只能起到说明作用,因为 AFAIK PostgreSQL 实际上并没有执行任何保证使用它们的计划。来自pgsql-hackers 邮件列表的following post 似乎支持我的主张:

无论如何,波动性对于触发功能来说都是完全无操作的,就像 其他计划器参数,例如成本/行,因为没有 触发调用中涉及的计划。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-01-24
    • 1970-01-01
    • 1970-01-01
    • 2017-08-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-10
    相关资源
    最近更新 更多