Немного про SLA для DWH на PostgreSQL

от автора

Описание проблемы

В некоторых случаях в DWH приходится периодическим заданием очищать таблицу и заполнять ее новыми актуальными данными. Например, раз в сутки. Если в таблице десятки или сотни тысяч строк, то это не проблема. А вот если миллиард — то уже точно проблема. Потому что каким бы способом ее не заполнять, но в течении достаточно длительного времени данные из этой таблицы не будут доступны пользователям. А если система должна быть доступна 24/7, то такие процессы начинают заметно ухудшать SLA.

Варианты решения

Один из вариантов решения — это свалить данную проблему на клиента. Создаем две таблицы одинаковой структуры. Периодическим заданием заполняем эти таблицы по очереди. Сегодня одну, завтра другую. В третьей таблице указываем, какая из этих таблиц актуальна на данный момент. Клиент же определяет нужную таблицу предварительным запросом к этой третьей таблице. Минус решения — динамический SQL на каждом клиенте и более сложная логика.

Второй вариант — через переименование таблиц. И именно он выглядит предпочтительней.

Описание решения

Нашу таблицу очищает и заполняет какая-то конкретная хранимая процедура. Назовем ее условно SomeScheme.ThisTablePeriodicFill_sp. Тогда у нас возникает логический ресурс to_regproc(‘SomeScheme.ThisTablePeriodicFill_sp’)::oid::integer, который мы и будем использовать для логических блокировок. Перед доступом к нашей таблице каждый клиент должен выполнить:

PERFORM pg_advisory_lock_shared(   to_regproc('SomeScheme.ThisTablePeriodicFill_sp')::oid::integer, 0);

А по окончании работы с нашей таблицей клиент должен освободить ресурс:

PERFORM pg_advisory_unlock_shared(   to_regproc('SomeScheme.ThisTablePeriodicFill_sp')::oid::integer, 0);

Теперь процедура SomeScheme.ThisTablePeriodicFill_sp может создать новую таблицу SomeScheme.ThisTable_Shadow совпадающую по структуре с таблицей SomeScheme.ThisTable, но без индексов. После чего, никому не мешая, заполнить эту таблицу и, после ее заполнения, создать для нее необходимые индексы.

Однако просто переименовать эту таблицу мало. Ведь индексы в PostgreSQL являются relation и их имена глобальны. Для решения этой проблемы имена индексов делаем всегда начинающиеся с имени таблицы (например, ThisTable_IndexName_Idx) и создаем такую хранимую процедуру:

CREATE OR REPLACE PROCEDURE SomeSchema.normalize_index_names_sp (   schema_name       varchar,   table_name        varchar,   from_index_prefix varchar ) AS $proc$ <<proc>> DECLARE   sql_str           varchar; BEGIN   SELECT string_agg('ALTER INDEX '     ||schema_name||'.'||indexname||' RENAME TO '||LOWER(table_name)     ||RIGHT(indexname,LENGTH(indexname)-LENGTH(from_index_prefix)),'; ')   INTO sql_str   FROM pg_catalog.pg_indexes   WHERE schemaname=LOWER(schema_name) AND tablename=LOWER(table_name)     AND indexname LIKE LOWER(from_index_prefix)||'%';   EXECUTE sql_str; END; $proc$ LANGUAGE plpgsql;

Используя данную процедуру мы получаем возможность быстро переименовать таблицы и их индексы:

PERFORM pg_advisory_lock(   to_regproc('SomeScheme.ThisTablePeriodicFill_sp')::oid::integer, 0); ALTER TABLE IF EXISTS SomeScheme.ThisTable RENAME TO ThisTable_Bak; CALL SomeScheme.normalize_index_names_sp (   'SomeScheme','ThisTable_Bak','ThisTable'); ALTER TABLE IF EXISTS SomeScheme.ThisTable_Shadow RENAME TO ThisTable; CALL SomeScheme.normalize_index_names_sp (   'SomeScheme','ThisTable','ThisTable_Shadow'); DROP TABLE IF EXISTS SomeScheme.ThisTable_Bak; PERFORM pg_advisory_unlock(   to_regproc('SomeScheme.ThisTablePeriodicFill_sp')::oid::integer, 0);

В данном коде опущен блок EXCEPTION, в котором при возникновении ошибок производится журналирование и попытка восстановить имя ThisTable.

Процесс переименования таблиц и их индексов в PostgreSQL выполняется очень быстро. Таким образом мы улучшаем SLA, сократив недоступность таблицы до времени ожидания в очереди, в худшем случае, на время логической блокировки (advisory_lock_shared) клиента, что намного меньше времени заполнения такой таблицы.


ссылка на оригинал статьи https://habr.com/ru/articles/765484/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *