Вставка данных в мастер-таблицу после раздела - PullRequest
0 голосов
/ 16 апреля 2020

Я работаю над таблицей базы данных в базе данных postgres, размер которой превышает 1 ТБ и в которой содержится около 2 миллиардов записей. Итак, я решил разделить таблицу на основе столбца «метка времени».

- Шаг 1. Создание таблиц разделов

CREATE TABLE bigtable_y2019 (
    CHECK (timestamp >= '2019-01-01' AND timestamp < '2020-01-01')
) INHERITS (bigtable);

CREATE TABLE bigtable_y2020 (
    CHECK (timestamp >= '2020-01-01' AND timestamp < '2021-01-01')
) INHERITS (bigtable);

- Шаг 2. Создание индекса для ключевого столбца (отметка времени)

CREATE UNIQUE INDEX bigtable_y2019_pkey ON bigtable_y2019 USING btree (id);
CREATE INDEX bigtable_y2019_timestamp ON bigtable_y2019 (timestamp);

CREATE UNIQUE INDEX bigtable_y2020_pkey ON bigtable_y2020 USING btree (id);
CREATE INDEX bigtable_y2020_timestamp ON bigtable_y2020 (timestamp); 

- Шаг 3 Создать функцию

CREATE OR REPLACE FUNCTION bigtable_insert_trigger()
RETURNS TRIGGER AS $$
BEGIN
IF (NEW.timestamp >= '2020-01-01' AND NEW.timestamp < '2021-01-01') THEN
        INSERT INTO bigtable_y2020 VALUES (NEW.*);
    ELSIF (NEW.timestamp >= '2019-01-01' AND NEW.timestamp < '2020-01-01') THEN
        INSERT INTO bigtable_y2019 VALUES (NEW.*);    
    ELSE
        RAISE EXCEPTION 'Date out of range.  Fix the bigtable_insert_trigger() function!';
    END IF;
    -- My understanding was this should have prevented inserting data into master table
    RETURN NULL;
END;
$$
LANGUAGE plpgsql;

- Шаг 4. Включить триггер ВКЛ ПЕРЕД ВСТАВИТЬ СОБЫТИЕ и выполнить функцию

CREATE TRIGGER insert_bigtable_trigger BEFORE INSERT ON bigtable FOR EACH ROW EXECUTE FUNCTION bigtable_insert_trigger();

- Шаг 5. Установите для enable_partition_pruning и contstraint_exclusion значение ON

SET enable_partition_pruning = ON;
SET constraint_exclusion = ON;

Эти шаги выше вставляют запись не только в дочернюю таблицу, но и в родительскую таблицу, которую я пытаюсь избежать.

Итак, я попытался создать еще один триггер для события AFTER INSERT, чтобы удалить родительская таблица. Это не лучший подход, но моя работа вокруг, чтобы увидеть, как это работает.

- Так как RETURN NULL в tripdetail_insert_trigger не избегает вставки в главную таблицу, я создал обходной путь для удаления этой записи из главной table.

CREATE OR REPLACE FUNCTION bigtable_mastertable_record_delete_trigger()
RETURNS TRIGGER AS $$
BEGIN
DELETE FROM ONLY bigtable WHERE id = NEW.id;
END;
$$
LANGUAGE plpgsql;

CREATE TRIGGER delete_bigtable_mastertable_record_trigger AFTER INSERT ON bigtable FOR EACH ROW EXECUTE FUNCTION bigtable_mastertable_record_delete_trigger();

Между родительской и дочерней таблицами есть syn c. Если запись вставляется в дочернюю таблицу, то же самое происходит и в родительской таблице, и если запись удаляется в одной из них, то запись удаляется также и в другой.

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

Ответы [ 2 ]

1 голос
/ 16 апреля 2020

enable_partition_pruning был добавлен в PostgreSQL 11. Если вы используете PostgreSQL 11, то почему бы вам не использовать возможность разбиения таблицы в PostgreSQL 11 https://www.postgresql.org/docs/11/ddl-partitioning.html

0 голосов
/ 21 апреля 2020

При использовании возможностей разбиения PostgreSQL 11 родительская таблица будет только определением и НЕ будет содержать никаких записей. См. Раздел Декларативное разбиение здесь https://www.postgresql.org/docs/11/ddl-partitioning.html#DDL -PARTITIONING-DECLARATIVE

Если у вас есть база данных, необходимо выполнить следующие шаги:

  1. Переименовать старую таблицу

    ALTER TABLE bigtable RENAME TO bigtable_pre_partitioning;

  2. Создать секционированную таблицу (определить структуру, индекс, ключ диапазона)

    CREATE TABLE bigtable (id int not null, дата входа не нулевая) PARTITION BY RANGE (logdate);

  3. Создать раздел

    CREATE TABLE bigtable_2020_01 РАЗДЕЛ bigtable ДЛЯ ЗНАЧЕНИЙ ОТ ('2020-01-01') TO ('2020-02-01');

  4. Создать другой раздел

    CREATE TABLE bigtable_2020_02 РАЗДЕЛ bigtable ДЛЯ ЗНАЧЕНИЙ ОТ ('2020 -02-01 ') TO (' 2020-03-01 ');

  5. Присоединить старый раздел (это занимает очень много времени в зависимости от того, сколько у вас данных)

    ALTER TABLE bigtable ATTACH PARTITION bigtable_pre_partitioning ДЛЯ ЗНАЧЕНИЙ ОТ (MINVALUE) ДО ('2020-01-01');

  6. Теперь вы можете вставлять записи непосредственно в родительский элемент bigtable, и они будут попадать в правильный раздел .

    INSERT INTO bigtable ...

Несколько замечаний:

  • Первичный ключ должен содержать ключ диапазона
  • Если вы создадите индекс для родительской таблицы -> новый раздел унаследует его
  • Если вы создадите ограничение для родительской таблицы -> новый раздел унаследует его
  • Вы можете создать таблицу по умолчанию, в которую попадают все записи, если у вас нет подходящего диапазона разделов

Надеюсь, это поможет. В приведенной выше статье содержится раздел о передовых методах, что весьма полезно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...