postgres触发器创建索引:BEFORE INSERT ON隐藏一行

时间:2017-05-22 09:46:50

标签: postgresql triggers postgresql-9.4

我有一个调用函数的触发器AFTER INSERT ON mytable

CREATE OR REPLACE FUNCTION myfunction() RETURNS trigger AS
$BODY$
    DECLARE
        index TEXT;
    BEGIN
        index := 'myIndex_' || NEW.id2::text;
        IF to_regclass(index::cstring) IS NULL THEN
            EXECUTE 'CREATE INDEX ' || index || ' ON mytable(id) WITH (FILLFACTOR=100) WHERE id2=' || NEW.id2|| ';';
            RAISE NOTICE 'Created new index %',index;
        END IF;
        RETURN NULL;
    END;
$BODY$
LANGUAGE plpgsql VOLATILE
SECURITY DEFINER
COST 100;
ALTER FUNCTION myfunction()
    OWNER TO theadmin;

这非常有用。对于每个不同的id2,我创建一个索引。通过大量加快相关查询。

如上所述,我触发此AFTER INSERT ON。在此之前,我将触发器设置为BEFORE INSERT ON。功能做了一些奇怪的事情。 (是的,我已将RETURN NULL更改为RETURN NEW

  • 插入新行insert into mytable VALUES(1391, 868, 0.5, 0.5);
  • 创建相应的索引myIndex_868
  • 执行选择时,mytable中插入的行不会出现 :(
  • 尝试插入相同的行会导致ERROR: duplicate key value violates unique constraint "mytable_pkey",因为当然DETAIL: Key (id, id2)=(1391, 868) already exists.
  • 为同一个id2插入其他行按预期工作:)
  • DELETE FROM mytable WHERE id = 1391 and id2 = 868什么都不做
  • DROP INDEX myIndex_868;删除索引。突然间,表中从未出现的最初一行突然出现了!

为什么BEFORE INSERT ON表现得如此不同?这是postgres 9.4中的错误还是忽略了什么?

只是为了完整'缘故:

CREATE TRIGGER mytrigger
AFTER INSERT ON mytable
FOR EACH ROW EXECUTE PROCEDURE myfunction();

VS

CREATE TRIGGER mytrigger
BEFORE INSERT ON mytable
FOR EACH ROW EXECUTE PROCEDURE myfunction();

1 个答案:

答案 0 :(得分:2)

我认为这是PostgreSQL中的一个错误。我可以用9.6重现它。

很明显,该行未包含在索引中,因为它是在BEFORE触发器中创建的,但是在插入行时索引未更新的事实是我认为的错误。 / p>

我有written to pgsql-hackers要求提出意见。

但除此之外,我没有看到整个演习的重点。 创建一个巨大的索引比创建一个单一的索引更好:

CREATE INDEX ON mytable(id2, id);