Наличие нескольких событий триггера при перенаправлении вставок в таблицы разделов - PullRequest
0 голосов
/ 17 января 2019

Я пытаюсь настроить триггеры для событий вставки и обновления для главной таблицы некоторых таблиц разделов в PostgreSQL. Каждый раз, когда выполняется вставка в основную таблицу, событие триггера вставки перенаправляет ее в правильную таблицу разделов. Следовательно, мне нужно будет вернуть NULL из этого вызова функции, так как я не хочу, чтобы основная таблица также заполнялась. Если главная таблица получает событие обновления, она обновит временную метку перед внесением изменений в таблицу. Проблема в том, что триггер обновления никогда не срабатывает. Я использую PostgreSQL версии 9.6.

Я попытался объединить триггерные функции в одну, и объединил вызванные триггерные процедуры в одну, но результаты совпадают. Триггер обновления срабатывает только в том случае, если я возвращаю NEW из функции триггера вставки (которая заполняет основную таблицу) или если я закомментирую функцию триггера вставки.

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;

Я не уверен, что с помощью этого метода можно добиться того, чего я хочу, поэтому я обращаюсь сюда за любыми советами. Заранее спасибо!

/ Хампус

1 Ответ

0 голосов
/ 17 января 2019

Триггеры строк должны быть определены на отдельных разделах, а не на секционированной таблице. Смотри 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;, вам может не потребоваться триггер обновления.

Разбиение не является бесплатным обедом, поскольку оно неочевидно влияет как на поведение, так и на производительность, как вы заметили, что триггер не ведет себя так, как вы ожидали. Если вы допустите ошибку, это может легко привести к ошибочным запросам и даже к неверным данным.

Если вы действительно уверены, что вам это нужно, вам следует убедиться, что вы понимаете это в деталях, а в противном случае я бы порекомендовал вам этого избегать, большинство проблем с медленными запросами можно решить, убедившись, что статистика таблицы обновлена, использование правильных индексов, оптимизация запросов, изменение конфигурации Postgres или добавление дополнительного оборудования.

...