PostgreSQL 15: Часть 3 или Коммитфест 2021-11

99bcdff066372633891f25bbcfc56c9e

Вместе с началом зимы, релизный цикл 15-й версии продвинулся еще на один, теперь уже третий, коммитфест. Напомню, что о предыдущих двух можно подробнее прочитать здесь: 2021–07, 2021–09.

Теперь же посмотрим, что происходило в последнем на текущий момент, ноябрьском коммитфесте.

Мониторинг


Журналирование работы процесса startup
commit: 9ce346ea

При запуске сервера основное время обычно уходит на синхронизацию каталога данных с диском (fsync), удаление нежурналируемых таблиц и применение файлов WAL.

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

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

Новые события ожидания для команд управления файловым архивом WAL
commit: 1b06d7ba

Пополнение в списке событий ожидания, относящихся к типу IPC: ArchiveCommand, ArchiveCleanupCommand, RestoreCommand, RecoveryEndCommand.

Каждое из ожиданий устанавливается на время выполнения команды shell соответствующего параметра конфигурации.

Функции для просмотра содержимого каталогов логической репликации
commit: 1922d7c6

Для мониторинга работы логической репликации могут пригодиться новые функции для просмотра соответствующих каталогов файловой системы:


Производительность


Сортировка данных: замена многофазного слияния на многопутевое сбалансированное слияние
commit: 65014000

Очередная оптимизация алгоритмов сортировки. В частности речь идет о внешней сортировке, представленной в планах запросов как «Sort Method: external merge».

Улучшения не очень значительные, но почитатели Кнута могут включить trace_sort и исследовать изменения, особенно на небольших значениях work_mem.

Индексы BRIN не блокируют HOT-обновления
commit: 5753d4ee

HOT-обновление не применяется, если хотя бы один изменяемый столбец команды UPDATE проиндексирован любым типом индекса.

Однако индексы BRIN не содержат ссылок на табличные строки. И использовать HOT для обновления столбцов с такими индексами вполне безопасно. Поэтому в 15-й версии индексы BRIN больше не будут препятствовать оптимизации HOT update:

15=# CREATE INDEX flights_bi ON flights USING brin(actual_departure);
15=# SELECT pg_stat_reset_single_table_counters('flights'::regclass);

15=# UPDATE flights SET actual_departure = actual_departure + '5 min'::interval
     WHERE flight_id = 1;

15=# SELECT n_tup_hot_upd FROM pg_stat_all_tables WHERE relname = 'flights';
 n_tup_hot_upd
---------------
             1


Процесс archiver и файлы в pg_wal/archive_status
commit: beb4e9ba

До определенных ситуаций дело лучше не доводить. Например, если команда из archive_command по каким-то причинам уже давно перестала копировать файлы в архив, а места в pg_wal хоть отбавляй.

Последствия будут такими: в каталоге pg_wal и, в частности, в pg_wal/archive_status накопится огромное количество файлов. При каждом запуске процесс archiver должен просканировать archive_status в поисках файла для архивирования, что может занять очень и очень много времени, хотя сама команда archive_command выполняется быстро. По сути, в такой ситуации процесс архивирования практически парализован.

Чтобы было немного полегче, процесс archiver будет запоминать сразу несколько файлов для архивирования, чтобы не сканировать каталог archive_status при каждом запуске. Но всё-таки до такой ситуации лучше просто не доводить.

Узел Gather: оптимизация пересылки строк от рабочих процессов
commit: 46846433

В параллельных запросах узел Gather теперь получает строки от рабочих процессов с меньшими затратами.

Разработчики серьезно подумывают над уменьшением parallel_tuple_cost, чтобы в новых реалиях планы с параллельным выполнением выбирались чаще.

starts_with и ^@: добавлена вспомогательная функция для планировщика
commit: a148f8bc

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

Такая вспомогательная функция была добавлена для функции starts_with и связанного с ней оператора ^@.

Увидеть изменения можно на оценке кардинальности простого запроса. Посмотрим, как часто имя Павел встречается в билетах.

14=# SELECT count(*) FROM tickets WHERE starts_with(passenger_name,'PAVEL');
 count
-------
 24090


А теперь что думает по этому поводу планировщик в 14-й версии:

14=# EXPLAIN SELECT * FROM tickets WHERE starts_with(passenger_name,'PAVEL');
                            QUERY PLAN                            
------------------------------------------------------------------
 Seq Scan on tickets  (cost=0.00..86286.54 rows=983241 width=104)
 ...


Как видно, оценка сильно неточная. А теперь в 15-й версии:

15=# EXPLAIN SELECT * FROM tickets WHERE starts_with(passenger_name,'PAVEL');
                                   QUERY PLAN                                   
--------------------------------------------------------------------------------
 Gather  (cost=1000.00..68502.23 rows=27236 width=104)
 ...


Почти идеально.

Дополнительный бонус для тех кто использует правило сортировки C. Функция starts_with, как и оператор ^@, смогут использовать не только индексы SP-GiST, но и Btree.

Процедурные языки


PL/pgSQL: локализация ошибок в секции инициализации
commit: acb2d7d5

Выполняем анонимный блок PL/pgSQL:

14=# DO $$DECLARE
   x int := 42;
   y int := 1/0;
   z text := 'Hello';
BEGIN
END; $$;
ERROR:  division by zero
CONTEXT:  SQL expression "1/0"
PL/pgSQL function inline_code_block line 5 during statement block local variable initialization


Понятно, что делить на 0 нельзя, но почему ошибка в 5-й строке?

А все потому, что любая ошибка в секции DECLARE помечается той строкой, где расположено слово BEGIN. И не важно при инициализации какой переменной произойдет ошибка, всё равно в сообщении строка останется пятой.

Откровенно говоря, неудобно. Было. А теперь:

15=# DO $$DECLARE
   x int := 42;
   y int := 1/0;
   z text := 'Hello';
BEGIN
END; $$;
ERROR:  division by zero
CONTEXT:  SQL expression "1/0"
PL/pgSQL function inline_code_block line 3 during statement block local variable initialization


Репликация


Логическая репликация всех таблиц схемы
commit: 5a283246

Задать список таблиц при создании публикации можно двумя способами. Либо явно перечислить, либо указать FOR ALL TABLES. Во втором случае в публикацию включаются все таблицы базы данных.

Но что если нужно реплицировать все таблицы определенных схем, но не всей базы данных? В 15-й версии это просто:

CREATE PUBLICATION bookings_pub FOR ALL TABLES IN SCHEMA bookings;


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

Новая таблица в схеме bookings автоматически добавится в публикацию. Правда на стороне подписки чуда не произойдет. Логическая репликация пока не умеет передавать команды DDL. Поэтому в базе данных подписчика придется создать таблицу и обновить подписку (ALTER SUBSCRIPTION… REFRESH PUBLICATION).

Описание от depesz.

pg_receivewal: поддержка lz4
commit: babbbb59, d62bcc8b

Утилита pg_receivewal, в дополнение к gzip, теперь поддерживает метод сжатия lz4 (если PostgreSQL был скомпилирован с параметром --with-lz4). Для выбора метода сжатия предназначен новый параметр утилиты pg_receivewal --compression-method.

Безопасность


Все три нововведения в этой группе относятся к теме администрирования сервера без использования полномочий суперпользователя.

Права доступа к pg_backend_memory_contexts и pg_shmem_allocations
commit: 77ea4f94

Предопределенная роль pg_read_all_stats получила доступ к представлениям pg_backend_memory_contexts и pg_shmem_allocations, а также к функциям, на основе которых эти представления созданы.

Права доступа к pg_log_backend_memory_contexts
commit: f0b051e3

С функции pg_log_backend_memory_contexts снята проверка на работу только под суперпользователем. Теперь суперпользователь может выдать права на выполнение этой функции любой роли.

Права доступа к CHECKPOINT
commit: 4168a474

Новая предопределенная роль pg_checkpointer дает право выполнить команду CHECKPOINT.

Разное


amcheck: проверки для TOAST
commit: bd807be6

В модуле amcheck новые проверки. Теперь перенесенные в TOAST значения проверяются на корректный размер и способ компрессии.

Новая реализация random
commit: 3804539e

Заменен, используемый функцией random, устаревший алгоритм генерации псевдо-случайных чисел на современный Xoroshiro128+. У нового алгоритма лучше статистические свойства, а реализация меньше зависит от платформы.

btree_gist: поддержка типа bool
commit: 57e3c516, e2fbb883

В длинный список поддерживаемых модулем btree_gist типов данных добавлен логический тип.


На этом пока всё. Продолжение следует после январского коммитфеста.

© Habrahabr.ru