将插入重定向到分区表时有多个触发事件

Having multiple trigger events when redirecting insertions to partition tables

我正在尝试为 PostgreSQL 中某些分区 table 的主 table 的插入和更新事件设置触发器。每次插入到主 table 时,插入触发事件会将其重定向到正确的分区 table。因此,我将需要从此函数调用中 return NULL,因为我不希望主 table 也被填充。如果 master table 接收到更新事件,它将在 table 中进行更改之前更新时间戳。问题是永远不会触发更新触发器。我正在使用 PostgreSQL 9.6 版。

我试过将触发函数合并为一个,将调用的触发过程也合并为一个,结果都是一样的。仅当我 return NEW 从插入触发器函数(填充主 table)或者如果我完全注释掉插入触发器函数时才会触发更新触发器。

DROP SCHEMA IF EXISTS test CASCADE;
CREATE SCHEMA test;
SET SCHEMA 'test';

CREATE TYPE test_type AS ENUM ('unit', 'performance');

CREATE TABLE test (
    type test_type NOT NULL,
    score INTEGER NOT NULL CHECK (score > 0),
    id SERIAL PRIMARY KEY,
    updated_at TIMESTAMP DEFAULT current_timestamp
);

CREATE TABLE performance_test (
    CHECK (type = 'performance')
) INHERITS (test);

CREATE FUNCTION insert_test()
RETURNS trigger AS
$$
BEGIN
    INSERT INTO performance_test VALUES (NEW.*);
    RETURN NULL;
END;
$$ LANGUAGE plpgsql;

CREATE FUNCTION update_timestamp()
RETURNS trigger AS
$$
BEGIN
    RAISE NOTICE 'This is never reached.';

    UPDATE performance_test
    SET updated_at = current_timestamp
    WHERE id = NEW.id;

    RETURN NULL;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER test_insertion BEFORE INSERT ON test
    FOR EACH ROW EXECUTE PROCEDURE insert_test();

CREATE TRIGGER test_update BEFORE UPDATE ON test
    FOR EACH ROW EXECUTE PROCEDURE update_timestamp();

---------------------------------------------------------------------------

INSERT INTO test VALUES ('performance', 10);

SELECT * FROM performance_test;

UPDATE test SET score = 20 WHERE id = 1;

SELECT * FROM performance_test;

我不确定用这种方法是否可以达到我想要的效果,所以我在这里寻求任何建议。提前致谢!

/汉普斯

行触发器必须在单独的分区上定义,而不是分区 table。参见 https://www.postgresql.org/docs/10/ddl-partitioning.html#DDL-PARTITIONING-DECLARATIVE-LIMITATIONS

我不知道为什么 9.6 的文档没有提到这个

工作更新触发器:

CREATE FUNCTION update_timestamp()
RETURNS trigger AS
$$
BEGIN
  NEW.updated_at = now();
  RETURN NEW;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER test_update BEFORE UPDATE ON performance_test
    FOR EACH ROW EXECUTE PROCEDURE update_timestamp();

如果您UPDATE test SET score = 30, updated_at=DEFAULT;UPDATE test SET score = 30, updated_at=current_timestamp;您可能不需要更新触发器。

分区不是免费的午餐,因为它对行为和性能都有不明显的影响,正如您注意到触发器的行为与您预期的不同。如果你犯了一个错误,很容易导致查询失败,甚至是错误的数据。

如果你真的确定你需要它,你应该确保你详细了解它,否则我建议你避免它,大多数查询慢的问题都可以通过确保 table统计信息是最新的、使用正确的索引、优化查询、更改 Postgres 配置或添加更多硬件。