Skip to content

postgrespro/pgpro_redefinition

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Реорганизация таблиц

Расширение предназначено для онлайн манипуляций с данными в больших таблицах без простоя (или с минимальным простоем, необходимым для создания служебных объектов).

Возможные манипуяции с данными:

  • Из одной большуй таблицы сделать секционированную таблицу;
  • Добавить колонку в таблицу со значением по умолчанию;
  • Перенос данных на другой сервер СУБД с использованием FDW;
  • Обогатить данные из внешней системы;
  • Таблицу из большого количества колонок переделать в 2 таблицы с нужным количеством колонок;

Краткое описание

Работа с таблицей состоит из нескольких частей частей.

  1. Ручное создание нужной табицы (или нескольких таблиц) с той же структурой или нескольких таблиц с нужной структурой. В случае, если структура таблицы, куда переносить данные, изменилась, необходимо создать процедура по переносу строки данных.
  2. Регистрация конфигурации, в которой описано откуда, куда и как копировать данные. В процедуре регистрации указывается источник, приемник и различныпе другие параметры.
  3. Копирования данных из существующей таблицы (источник) в новую таблицу (приемник). При копировании строки
    блокируются маленькими порциями (например по 1000 строк) на время, необходимое на вставку порции строк в таблицу приемник.

Режимы работы

Существует два режима работы

  • Онлайн перенос данных - для захвата изменений создаются триггеры и в той же транзакции, где происходит работа с основной таблицей, данные копируются в таблицу приемника. Параллельно запускается процедура копирования данных из основной таблицы маленькими порциями.
  • Отложенный перенос данных - для захвата изменений данные в триггерах копируются в таблицу изменений (mlog). Запускается процедура копирования данных из основной в таблицу изменений (mlog).
  • Из таблицы изменений данные применяются в таблицу приемник.

Рекомендации по выбору режима работы

  • Онлайн перенос данных рекомендается использовать для создания копии таблицы на том же сервере СУБД, когда гарантированно нет задержек при применении данных.

  • Отложенный перенос данных рекомендуется применять, если есть тяжелые операции работы с данными, например нужно пересчитать поле или сходить во внешнюю систему для обогощения данных. Так же отложенный перенос рекомендуется применять при созадании копии таблицы на внешнем сервере СУБД.

Описание пользователльский функций

pgpro_redefinition.register_redef_table

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

Параметры

configuration_name - имя концигурации, текстовое поле, должно быть уникальным в рамках сервера СУБД.

  • type - тип конфигурации - онлайн преобразование данных или отложенное преобразование.

    • pgpro_redefinition._type_online() - данные сразу копируются в таблицу назначения.
    • pgpro_redefinition._type_deferred() - данные копируются в таблицу изменений (mlog таблица), позднее в таблицу назначения.
  • kind - вид конфигуркции -

    • pgpro_redefinition._kind_redef() - таблица приемник должна существовать. Данные копируются в таблицу приемник.
    • pgpro_redefinition._kind_any() - любое действие с данными таблицы, можно копировать, можно разбить на 2 и более таблиц. Таблица приемник не устанавливается. Вся логика описывается в callback функции.
  • source_table_name - имя таблицы источника. Задается всегда.

  • source_schema_name - имя схемы источника. Задается всегда.

  • dest_table_name - имя таблицы приемника. Может отсутствовать. -- todo - описать, когда может отсутствовать.

  • dest_schema_name - имя схемы приемника. Может всегда. -- todo - описать, когда может отсутствовать.

  • callback_name - процедура, которая переопределяет данные. В этой функции можно задать любое преобразованияе над строкой. Если callback не задан, создается процера, которая переносить данные один в один.

  • callback_schema_name - имя схемы callback процедуры.

  • dest_pkey - первичный ключ таблицы приемника. В некоторых случаях необходимо указать. todo - описать случаи, когда первичный ключ нужен. Задается в формате jsonb, например dest_pkey=>'[{"pos": 1, "name": "id1", "type": "bigint"}, {"pos": 2, "name": "id2", "type": "bigint"}]'::jsonb $$

  • rows_redef - количество строк, которые будут обработаны за один раз в одной транзации при копировании данных.

  • rows_apply - количество строк, которые будут применяться в одной транзакции, в случает работы с таблицей изменений.

  • loop_redef - кол-во циклов, запускаемых в одной процедуре при копировании данных.

  • loop_apply - кол-во циклов, запускаемых в одной процедуре при применении данных из таблицы изменений (mlog).

  • sleep_redef - время сна после применения rows_redef. Параметр для снижения нагрузки на СУБД.

  • sleep_apply - время сна после применения rows_apply. Параметр для снижения нагрузки на СУБД.

  • weight - -- Вес конфигарациии при работе с большим количеством таблиц. todo - параметр не работает.

Пример callback функции

pgpro_redefinition._kind_redef()

Обязательное копирование данных из одной таблицы в другую

create or replace function public.callback__table01 (
    source_old        source_schema.source_table
,   source_new        source_schema.source_table
,   dest_old out      dest_schema.dest_table
,   dest_new out      dest_schema.dest_table
) as
$redef$
declare
begin
    dest_old.id := source_old.id;
    dest_old.type := source_old.type;
    dest_old.data := source_old.data;

    dest_new.id := source_new.id;
    dest_new.type := source_new.type;
    dest_new.data := source_new.data;
end;
$redef$
language plpgsql;

pgpro_redefinition._kind_any()

Любые преобразования данных. Копирование данных задается в самой процедуре/функции В преобразовании any все действия с данными пользователь прописывает САМ в callback процедуре. Процедура вызывается в тригерах и в момент копирования данных, ничего не возвразает.

create or replace function public.callback__table01 (
    source_old        source_schema.source_table
,   source_new        source_schema.source_table
)   returns void
as
$redef$
declare
begin
    if source_old is null then
            insert into dest_fdw.dest_test01_table01 (
                    id1
                ,   id2
                ,   type
                ,   data
                ,   typy_data
                )
                values (
                    source_new.id1
                ,   source_new.id2
                ,   source_new.type
                ,   source_new.data
                ,   coalesce(source_new.type, ' - ') || ' updated ' || coalesce(source_new.data, ' - ')
                );
    elsif source_new is null then
            delete from dest_fdw.dest_test01_table01 where id1 = source_old.id1 and id2 = source_old.id2;
    elsif source_new <> source_old then
            update dest_fdw.dest_test01_table01
            set id1 = source_new.id1
            ,   id2 = source_new.id2
            ,   data = source_new.data
            ,   type = source_new.type
            ,   typy_data = coalesce(source_new.type, ' - ') || coalesce(source_new.data, ' - ')
            where id1 = source_old.id1 and id2 = source_old.id2;
    end if;
end;
$redef$
language plpgsql;

Статусы

Статусы (redef_table.status) всей конфигурации

  • Любая работа с данными возможна в статусе registered.
  • При переходе статуса в finished:
    • проверяется, что ВСЕ данные скопированы или перенесены
    • все задания завершаются
    • созданные ранее объекты (функции, триггера и другие) удаляются
    • данные из таблиц переносятся в таблицы со поствиксом _archive
    • при необходимости, таблица источник заменяется на таблицу приемника (переименование)
  • При переводе в aborted:
    • задания завершается неуспешно
    • созданные ранее объекты (функции, триггера и другие) удаляются
    • данные из таблиц переносятся в таблицы со поствиксом _archive

Переходы

stateDiagram-v2
   new         -->   registered
   registered   -->   finished
   registered   -->   aborted
Loading

Статусы копирования данных

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

Переходы

captured = true

stateDiagram-v2
   started    -->   pause
   started    -->   finished
   pause      -->   finished
   pause      -->   started
   pause      -->   aborted
   started    -->   aborted
Loading

Статусы применения mlog

Применение данных возможно только после начала сохранения данных в mlog.

Переходы

captured = true

stateDiagram-v2 
   started    -->   pause
   started    -->   finished
   pause      -->   finished
   pause      -->   started
   pause      -->   aborted
   started    -->   aborted
Loading

Жизненный цикл online преобразования

stateDiagram-v2 
   register_table           -->   start_capture_data
   start_capture_data       -->   start_redef_table
   start_capture_data       -->   abort_table
   start_capture_data       -->   finish_table
   start_redef_table        -->   pause_redef_table
   pause_redef_table        -->   start_redef_table
   pause_redef_table        -->   abort_table
   pause_redef_table        -->   finish_table
   start_redef_table        -->   abort_table
   start_redef_table        -->   finish_table   
Loading

Жизненный цикл deferred преобразования

Добавляется применение данных из mlog таблицы

stateDiagram-v2 
   register_table           -->   start_capture_data
   start_capture_data       -->   start_redef_table
   start_capture_data       -->   abort_table
   start_capture_data       -->   finish_table
   start_redef_table        -->   pause_redef_table
   pause_redef_table        -->   start_redef_table
   pause_redef_table        -->   abort_table
   pause_redef_table        -->   finish_table
   start_redef_table        -->   abort_table
   start_redef_table        -->   finish_table   
Loading

Варианты использования

Секционировать большую таблицу

Необходимо секционировать таблицу по hash. Исходная таблица.

drop table if exists table1;
drop sequence if exists seq_table1_id;
create sequence seq_table1_id;
create table table1 (
    id          bigint primary key  default nextval('seq_table1_id')
,   data        text default md5(random()::text)::text
);
insert into table1 select  from generate_series(1,10000) g;
  1. Необходимо создать вспомогатульную (interim) таблицу с нужными полями, которые полностью повторяют структуру исходной таблицы. Последовательности, от которых завися, которая используется в качестве первичного ключа лучше взять из основной таблицы.
drop table if exists interim_table1;
create table interim_table1 (
    id          bigint primary key default nextval('table1_pkey')
,   data        text default md5(random()::text)::text
) partition by hash (id);
create table interim_table1_p1 partition of interim_table1 for values with (modulus 2, remainder 0);
create table interim_table1_p2 partition of interim_table1 for values with (modulus 2, remainder 1);
  1. Регистрация таблицы. Обязательно нужно указыввать схемы источника и приемника.
call pgpro_redefinition.register_table(
    configuration_name                  => 'conf_table1'
,   type                                => pgpro_redefinition._type_online()
,   kind                                => pgpro_redefinition._kind_redef()
,   source_table_name                   => 'table1'
,   source_schema_name                  => 'public'
,   dest_table_name                     => 'interim_table1'
,   dest_schema_name                    => 'public'
);

После регистрации создаются различные объекты, которые используются для работы с данными.

  1. Начать захват изменений.
call pgpro_redefinition.start_capture_data(
    configuration_name                  => 'conf_table1'
);

При DML операциях в основную таблицу, операции дублируются во вспомогательную таблицу.

  1. Начать копирование данных.
call pgpro_redefinition.start_redef_table(
    configuration_name => 'conf_table1'
);

Копирование идет маленькими порциями. Посмотреть выполненные операции можно в таблице

select * 
from pgpro_redefinition.inc_stat
where configuration_name = 'conf_table1'
order by  ts_start desc ;

Как только поле dest_inserted равно 0, значит копирование данных завершено.

  1. После заверения копирования вызывается процедура pgpro_redefinition.finish_table и переименовать старую таблицу на новую. Старую таблицу можно удалить.
call pgpro_redefinition.finish_table(
    configuration_name => 'conf_table1'
);
alter table table1 rename to table1_tmp2;
alter table interim_table1 rename to table1;
drop table table1_tmp2;

Дальше таблицей можно пользоваться как обычной таблицей.

В случае, если необходимо прервать процесс, вызываетя процедура pgpro_redefinition.abort_table.

call pgpro_redefinition.abort_table(
    configuration_name => 'conf_table1'
);

todo

  • Добавить поддержку ванилы - примеры команд по запуску на нужных функций на баше.
  • Оформить как расширение.
  • Проверка callback функций на соответсвие требуемым параметрам.
  • Добавить min_jobs, max_jobs - а как регилировать кол-во заданий в зависимости от нагрузки.
  • Регистровать кол-во заданий в зависимости от времени - from 8:00 to 19:00 - jobs = 1, from 19:00 to 08:00 - jobs = 8.
  • Добавить sql_predicate - sql предикат, который добавляется в фукцию и триггер, который фильтрует данные.
  • Флаг, останавливающий выполнения заданий репликации (ВСЕХ заданий).
  • Протестить на учебной бд аэрофлота.
  • Поправить права на вызов ф-ий.
  • В случае неудачной репликации - показать, сохранить и обработать ошибку (реализовать операцию для возврата БД-источника в работу)
  • Отлов ошибок в loop ф-ии, если ошибка deadlock, повтор n(5) раз. Loop не более 60 раз.
  • Нагрузочные тесты.
  • Оптимизации - задачи на исследование.
    • При удалении хранить только первичный ключ
    • Оптимизация индекса - индекс не отдает место при vacuum
      • Первичный ключ на mlog - попробовать оставить индекс только на lsn и pos
    • При применении mlog - передавать на приемник массив или json - и на приемнике запускать что-то что сделает нужную работу с данными сразу на приемнике (создавтаь временную таблицу и делать запрос из временной таблицы)
    • Распараллеливание при применении вставке данных в приемник.
    • БД проводит много времени в idle_in_transaction_time (select datname, idle_in_transaction_time from pg_stat_database)
  • Функционал и тест по работе с большим количеством таблиц не готов.

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy