Жизненный цикл нововведений 14 версии состоит из 5 коммитфестов. Первый из которых — июльский — уже завершился, а значит есть что обсудить.
Принятых изменений было намного больше, чем будет описано. Рассмотрены в основном патчи с новым или измененным функционалом СУБД. Именно такие изменения представляют наибольший интерес для пользователей PostgreSQL. А то что не попало, как правило, относится к следующим категорям: исправления ошибок, рефакторинг, инфраструктура проекта, документация(почти всегда), комментирование кода, тестирование.
Да и вообще, цель описать абсолютно всё не ставилась. Отслеживание изменений в точности — очень трудоемкий процесс. Поэтому к решению важных задач, таких как переход на новую версию, всегда нужно готовиться по замечаниям к выпуску. А сейчас можно просто расслабиться и почитать «вести с полей» разработки. Если появится желание самостоятельно попробовать новинки, то придется собирать PostgreSQL из исходных кодов. А вот документация на принятые патчи доступна онлайн.
Вполне возможно в описание вкрались неточности. Поэтому для удобства читателей приведены ссылки на запись в коммитфесте, а также идентификаторы коммитов в git. При любых сомнениях стоит перепроверить оригинал и написать в комментариях о найденных недочетах.
Итак, начинаем.
Новости PostgreSQL 13
Статья про новости 14 версии, но как ни странно, первая группа патчей относится именно к 13 версии. Дело в том, что после апрельской заморозки кода функционал некоторых новшеств был изменен и об этом стоит упомянуть.
pg_stat_activity.leader_pid IS NULL для ведущего процесса
commit: 11a68e
После заморозки кода 13 версии изменились правила заполнения нового столбца leader_pid в pg_stat_activity — номер ведущего процесса при выполнении параллельных запросов. Первоначально предполагалось заполнять этот столбец не только для всех рабочих процессов, участвующих в выполнении запроса, но и для самого ведущего процесса. Теперь у ведущего процесса leader_pid будет оставаться незаполненным.
Документация: новое форматирование таблиц в главе «Функции и операторы»
commit: e894c61
Таблицы на официальном сайте для 13 и последней разрабатываемой версии уже выглядят в новом стиле. Такое оформление таблиц занимает больше места, но лучше подходит для вывода в другие форматы, например в PDF. Для сравнения можно посмотреть на форматирование математических функций и операторов в новом и старом стиле.
Параметра wal_keep_segments больше нет
commit: c3fe108
Вместо него wal_keep_size. Теперь нужно оперировать не количеством сегментов в pg_wal, а их размером. Сделано для унификации с новым для 13 версии параметром max_slot_wal_keep_size — максимальный размер файлов WAL, сохраняемых для слотов репликации.
Мимо этого изменения не смог пройти depesz в своей новой серии Waiting for PostgreSQL 14. Но изменение попадет и в 13 версию, начиная с beta3.
pg_validatebackup > pg_verifybackup
commit: dbc60c5
Новая для 13 версии утилита pg_validatebackup после заморозки кода переименована и будет называться pg_verifybackup.
sslminprotocolversion > ssl_min_protocol_version, sslmaxprotocolversion > ssl_max_protocol_version
commit: 401aad6
Новые для 13 версии параметры sslminprotocolversion и sslmaxprotocolversion переименованы: ssl_min_protocol_version и ssl_max_protocol_version.
ALTER… NO DEPENDS ON EXTENSION ...
commit: 5fc7039
В версии 9.6 добавили команду ALTER… DEPENDS ON EXTENSION… для указания, что объект зависит от расширения. Но забыли реализовать обратный вариант команды на снятие зависимости. Упущение исправлено и портировано в 13 версию. Из-за отсутствия жалоб портировать в более ранние версии не стали.
Новый параметр hash_mem_multiplier
commit: d6c08e2
Возможность не выходить за установленные пределы оперативной памяти(work_mem) при создании хеш-таблицы появилась еще на момент заморозки кода 13 версии. Если на этапе выполнения запроса окажется, что планировщик ошибся в оценках и work_mem не хватает — будут использоваться временные файлы. Это хорошо, т.к. нынешнее поведение — использовать столько памяти, сколько потребуется, а это не всегда приятное соревнование с OOM-killer.
Для управления поведением планировщика предлагались параметры enable_groupingsets_hash_disk и enable_hashagg_disk. К моменту выпуска 13 beta2 оба параметра заменили на hashagg_avoid_disk_plan. Но и этого оказалось недостаточно. Теперь вместо hashagg_avoid_disk_plan появился hash_mem_multiplier.
Название взято по аналогии с bgwriter_lru_multiplier и представляет собой множитель, на который планировщик умножает work_mem, чтобы получить объем памяти, который может использоваться для операции хеширования. Значение по умолчанию 1, что не меняет предыдущего поведения — память для хеширования не должна превышать work_mem.
Управляя этим параметром, и не меняя work_mem, можно дать планировщику больше шансов выбрать варианты с хеш вместо менее требовательных к наличию свободной памяти сортировок (в частности hash join вместо merge join).
EXPLAIN ANALYZE: изменения в формате вывода узла HashAggregate
commit: 0e3e1c4
А вот как будут выглядеть операции хеширования в плане запроса. Посмотрим на примере такого запроса к демо-базе:
EXPLAIN (ANALYZE) SELECT tf.fare_conditions, count(*)
FROM ticket_flights tf GROUP BY tf.fare_conditions;
Ограничимся лишь фрагментом плана с узлом HashAggregate.
Версия 12:
-> Partial HashAggregate
Group Key: fare_conditions
-> Parallel Seq Scan on ticket_flights tf
Версия 13beta2:
-> Partial HashAggregate
Group Key: fare_conditions
Peak Memory Usage: 24 kB
Worker 0: Peak Memory Usage: 24 kB
Worker 1: Peak Memory Usage: 24 kB
-> Parallel Seq Scan on ticket_flights tf
Теперь:
-> Partial HashAggregate
Group Key: fare_conditions
Batches: 1 Memory Usage: 24kB
Worker 0: Batches: 1 Memory Usage: 24kB
Worker 1: Batches: 1 Memory Usage: 24kB
-> Parallel Seq Scan on ticket_flights tf
Чтобы не играть в игру «найди 10 отличий» вот они, и их 5:
- счетчик пакетов (batches) начинается с 1, а не 0;
- Batches выводится всегда, даже если пакет был всего 1;
- для текстового формата выводится Batches вместо HashAgg Batches;
- для текстового формата выводится Memory Usage вместо Peak Memory Usage;
- Batches выводится перед Memory Usage
Изменение особенно важно для тех, кто разрабатывает свои инструменты для анализа плана запросов.
Отслеживание пауз в работе очистки
commit: cedffbd
Паузы в работе очистки ([autovacuum_]vacuum_cost_delay) теперь отображаются в pg_stat_activity.wait_event_type=Timeout и wait_event=VacuumDelay. До этого считалось что процесс ничего не ждет и столбцы wait_enent* были не заполнены.
Хватит о 13 версии, начиная со следующего раздела переходим к эксклюзиву версии 14.
Клиентские приложения
vacuumdb --no-truncate --no-index-cleanup
commit: 9550ea3
Утилита vacuumdb получила два новых аргумента командной строки: --no-truncate и --no-index-cleanup. С их помощью можно отключать соответствующие параметры VACUUM, появившиеся в 12 версии: TRUNCATE (нужно ли уменьшать файл, если последние страницы полностью очищены) и INDEX_CLEANUP (нужно ли выполнять очистку индексов).
Мониторинг и управление
pg_stat_statements: отслеживание количества обработанных строк у некоторых служебных команд
commit: 6023b7e
Раньше для команд CREATE TABLE AS, SELECT INTO, CREATE MATERIALIZED VIEW, FETCH в pg_stat_statements.rows не фиксировалось количество обработанных записей. Теперь эта информация стала доступна:
CREATE TABLE bookings_copy AS SELECT * FROM bookings;
SELECT 262788
SELECT query,rows FROM pg_stat_statements
WHERE query LIKE 'CREATE TABLE bookings_copy%';
query | rows
------------------------------------------------------+--------
CREATE TABLE bookings_copy AS SELECT * FROM bookings | 262788
Новые столбцы в pg_prepared_statements: generic_plans, custom_plans
commit: d05b172
В pg_prepared_statements появилась информация о количестве запросов, выполненных с общим и частным планом. Следующая цель — добавить такую же информацию в pg_stat_statements.
По умолчанию (plan_cache_mode = auto), если после пяти планирований запроса планировщик видит, что общий план будет не хуже частного, то он переходит на общий план, минимизируя свою работу. В следующем примере подготовленный запрос выполняется семь раз и после пятого повторения последние два раза выполняются уже с общим планом:
\d pg_prepared_statements
View "pg_catalog.pg_prepared_statements"
Column | Type | Collation | Nullable | Default
-----------------+--------------------------+-----------+----------+---------
name | text | | |
statement | text | | |
prepare_time | timestamp with time zone | | |
parameter_types | regtype[] | | |
from_sql | boolean | | |
generic_plans | bigint | | |
custom_plans | bigint | | |
PREPARE q(text) AS SELECT count(*) FROM bookings WHERE book_ref = $1;
SELECT $$EXECUTE q('ABCDEF')$$ FROM generate_series(1,7)\gexec
SELECT generic_plans, custom_plans FROM pg_prepared_statements WHERE name = 'q';
generic_plans | custom_plans
---------------+--------------
2 | 5
Доступ не суперпользователям к функциям, работающим с источниками репликации
commit: cc07264
Функциями, работающим с источниками репликации (pg_*replication_origin*), теперь могут пользоваться не только суперпользователи. Ранее проверка на суперпользователя была жестко зашита в коде. Проверку убрали и отобрали права на исполнение у public. Теперь суперпользователь может командой GRANT выдать разрешение на выполнение этих функций любым пользователям. Это в том числе дает возможность запрашивать данные из представления pg_replication_origin_status обычным пользователям.
В начале переписки рассматривалась идея предоставить роли pg_monitor доступ к pg_replication_origin_status. Но это в настоящий момент не реализовано.
Функция pgstattuple_approx поддерживает таблицы TOAST
commit: ee0202d
Функция pgstattuple_approx предоставляет приблизительную, но более быструю, альтернативу функции pgstattuple из одноименного расширения для оценки распухания объектов базы данных. Ускорение обеспечивается тем, что таблица сканируется не целиком, а с учетом карты видимости и карты свободного пространства. До 14 версии примерную оценку нельзя было получить для таблиц TOAST. Теперь это исправлено.
Производительность
У этой группы патчей есть очень хорошая особенность. Как правило, для получения лучшего быстродействия ничего не нужно делать. Просто переходим на новую версию и всё начинает работать быстрее. Хотя для некоторых изменений предусмотрены «ручки» (параметры), которые нужно научиться аккуратно подкручивать для получения наилучшего результата.
Кажется, что для описания увеличения производительности хорошо бы привести результаты замеров. Но их не будет. Во-первых, это достаточно сложная работа, требующая очень тщательной подготовки, разработки методики и описания условий проведения тестов. А во-вторых, какие бы впечатляющие результаты не приводились в замерах, они всё равно получены на некой абстрактной системе. И полностью доверять им не стоит. Любую оптимизацию нужно проверять на своей собственной системе и нагрузке. Поэтому поверим разработчикам PostgreSQL, которые на своих тестах получили положительные результаты.
Оптимизация добавления записей в каталоги pg_attribute и pg_shdepend
commit: e3931d0
Добавление набора записей в pg_attribute, например при создании таблицы, теперь выполняется за один раз. По словам разработчиков, в некоторых случаях это приводит к 15% сокращению записи в WAL. Такая же оптимизация для pg_shdepend.
Оптимизировано выполнение операторов PL/pgSQL
commit: 1f902d4, fe2e206
PL/pgSQL стал чуть быстрее. Правда, это не особенно заметно на архитектуре x86_64, а вот aarch64 выиграла однозначно.
Оптимизация RETURN QUERY в PL/pgSQL
commit: 2f48ede
Оптимизирована не только выдача результата запроса из функции, но и добавлена возможность параллельного выполнения запросов в RETURN QUERY, RETURN QUERY EXECUTE.
Создадим функцию с оператором RETURN QUERY.
CREATE FUNCTION get_fc(OUT fare_conditions varchar, OUT total bigint)
RETURNS SETOF RECORD AS $$
BEGIN
RETURN QUERY SELECT tf.fare_conditions, count(*)
FROM ticket_flights tf GROUP BY tf.fare_conditions;
END;
$$ LANGUAGE plpgsql STABLE PARALLEL SAFE;
Подключим auto_explain для получения плана запроса и выполним функцию:
SET auto_explain.log_min_duration = 0;
SET auto_explain.log_nested_statements = on;
SELECT * FROM get_fc();
В журнале видим, что использовался план с параллельным выполнением:
\! tail -n18 logfile
2020-08-06 23:23:34.825 MSK [17278] LOG: duration: 80.701 ms plan:
Query Text: SELECT tf.fare_conditions, count(*)
FROM ticket_flights tf GROUP BY tf.fare_conditions
Finalize GroupAggregate (cost=16250.86..16251.62 rows=3 width=16)
Group Key: fare_conditions
-> Gather Merge (cost=16250.86..16251.56 rows=6 width=16)
Workers Planned: 2
-> Sort (cost=15250.84..15250.85 rows=3 width=16)
Sort Key: fare_conditions
-> Partial HashAggregate (cost=15250.79..15250.82 rows=3 width=16)
Group Key: fare_conditions
-> Parallel Seq Scan on ticket_flights tf (cost=0.00..13072.19 rows=435719 width=8)
2020-08-06 23:23:34.825 MSK [17278] CONTEXT: SQL statement "SELECT tf.fare_conditions, count(*)
FROM ticket_flights tf GROUP BY tf.fare_conditions"
PL/pgSQL function get_fc() line 3 at RETURN QUERY
2020-08-06 23:23:34.825 MSK [17278] LOG: duration: 82.101 ms plan:
Query Text: SELECT * FROM get_fc();
Function Scan on get_fc (cost=0.25..10.25 rows=1000 width=40)
Выделение «быстрой» динамической разделяемой памяти для параллельных запросов
commit: 84b1c63
Когда для общей разделяемой памяти используются огромные страницы, новым параметром min_dynamic_shared_memory при запуске сервера можно выделить область динамической разделяемой памяти для параллельно выполняемых запросов. Используя эту «быструю» память, параллельные запросы выполняются существенно эффективнее. Если этой области памяти им не хватит, то будет выделяться дополнительная память способом указанным в dynamic_shared_memory_type, но ускорения уже не получится.
Параллельные запросы: данные в узле Gather обрабатываются более эффективно
commit: cdc7169
И этим всё сказано. Никаких настроек, параллельные запросы станут работать быстрее.
Все функции в расширении btree_gist помечены как PARALLEL_SAFE
commit: d98c08c
Теперь запросы, использующие операторы этого расширения, могут выполняться в параллельном режиме.
Оптимизация ввода-вывода для параллельного последовательного сканирования
commit: 56788d2
Раньше рабочие процессы получали на обработку по одному блоку за раз. Теперь получают порциями, размер которых зависит от размера таблицы. Тестирование патча показало хорошие результаты на дисках SSD для операционных систем Linux, FreeBSD, Windows. Однако для облачных провайдеров результаты не столь очевидны.
Кеширование размера файлов отношений при восстановлении
commit: c5315f4
При восстановлении, за счет кеширования, существенно сократилось количество вызовов, вычисляющих размер файлов lseek(SEEK_END). А это сокращение дисковых операций. Реплики работают в режиме восстановления всегда только в один процесс. Любая оптимизация здесь к месту.
COPY FROM в двоичном формате стала быстрее
commit: 0a0727c
Увеличена производительность загрузки данных командой COPY FROM в двоичном формате. В частности простые тесты показали ускорение на 30% в Linux, еще больше в MacOS.
COPY FROM в двоичном формате расходует меньше памяти
commit: cd22d3c
Еще одно небольшое улучшение для COPY FROM в двоичном формате позволяет сэкономить ~ 65Кб оперативной памяти на запуск.
Репликация
Логическая репликация сможет передавать данные в двоичном формате
commit: 9de77b5
Это изменение делает логическую репликацию быстрее. При создании/изменении подписки можно запросить у сервера публикации передачу в двоичном формате:
CREATE|ALTER SUBSCRIPTION … WITH (BINARY = ON)
По умолчанию двоичный формат отключен. После включения двоичные данные будут передаваться для тех типов, у которых определены функции send/receive. В противном случае используются функции указанные для input/output.
Сервер
Системные функции получения информации и адресации объектов возвращают NULL для несуществующих объектов
commit: 2a10fdc
В предыдущих версиях вызов подобных функций приводил к ошибке:
SELECT pg_describe_object('pg_class'::regclass, 0::oid, 0);
ERROR: cache lookup failed for relation 0
Но ошибка cache lookup failed предназначена для внутреннего использования и не должна быть видна пользователям. Все видимые типы ошибок описаны в документации. Теперь запрос возвращает NULL.
Изменение будет полезно тем, кто пишет собственные инструменты/скрипты для работы с системным каталогом.
Управление размером огромных страниц
commit: d2bddc2
Новый параметр huge_page_size для управления размером огромных страниц. По умолчанию 0, размер огромных страниц определяется настройками ОС.
У типа numeric появились значения «бесконечность» и «минус бесконечность»
commit: a57d312
Поведение такое же как и у соответствующих значений для типов с плавающей точкой. Это дает возможность конвертировать значения с плавающей точкой (и интерфейсы их использующие) в числа с произвольной точностью.
Разное
Добавлен метод amadjustmembers для проверки членов класса операторов
commit: 9f96827
Началось всё с того, что в расширении intarray оказалось невозможным средствами SQL удалить оператор <@ из класса операторов для GiST. В результате был доработан интерфейс для индексных методов доступа. В частности появилась функция amadjustmembers. Расширение intarray пока осталось без изменений.
Операторы + и ? для типа pg_lsn
commit: 9bae7e4
Еще не успели попробовать появившиеся в 13 версии агрегатные функции min и max для типа данных pg_lsn, как в 14-ю версию добавили арифметические операторы для добавления/вычитания байтов:
SELECT w.lsn, w.lsn +1, w.lsn -1 FROM (SELECT pg_current_wal_lsn()) AS w(lsn);
lsn | ?column? | ?column?
-----------+-----------+-----------
0/EF04B78 | 0/EF04B79 | 0/EF04B77
Получение информации об источнике репликации для транзакции
commit: b1e48bb
Источник репликации можно получить новой функцией pg_xact_commit_timestamp_origin. Эту же информацию добавили в pg_last_committed_xact.
Чтобы получить информацию о времени фиксации транзакции и источнике репликации должен быть включен параметр track_commit_timestamp:
SHOW track_commit_timestamp;
track_commit_timestamp
------------------------
on
SELECT pg_current_xact_id();
pg_current_xact_id
--------------------
721
SELECT * FROM pg_xact_commit_timestamp_origin('721'::xid);
timestamp | roident
-------------------------------+---------
2020-08-10 13:57:18.103297+03 | 0
SELECT * FROM pg_last_committed_xact();
xid | timestamp | roident
-----+-------------------------------+---------
721 | 2020-08-10 13:57:18.103297+03 | 0
На этом пока всё. Продолжение следует после сентябрьского коммитфеста.
rrrad
Таблицы в доке зря переиначили. С телефона искать глазами очень неудобно в новой версии.
vazir
Ради форматирования и перевода в др.форматы, уничтожили читабельность. Молодцы, нечего сказать. Лучше бы комменты реализовали в документации.
DmitryKoterov
Комменты в документации — это один из столпов, на которых стоит невероятная популярность PHP, кстати. Странно, что еще не все их делают.
eumorozov
Вряд ли комментарии сыграли в этом хоть какую-то роль. Когда PHP появился, у него был самый низкий порог входа: на всех других языках программирования требовалось изучать какие-то интерфейсы типа CGI, часто писать самостоятельно значительную часть обработки HTTP запросов и генерации ответов, тогда как в PHP ничего этого делать не надо было. Объективно, сложность написания простейшего скрипта на PHP была на порядки меньше, чем на любом другом языке.
Потом другие языки несколько догнали в плане лёгкости, появились различные фреймворки и упростилась процедура подключения приложения к веб-серверу. Но до сих пор это требует всё же несколько более усилий, чем просто забросить файл в почти любое место на веб-сервере. Пускай, это будет адская мешанина HTML и PHP, в которой через год уже не разобраться, но это не имеет значения для человека, который вообще не хочет читать документацию.
Мне сложно понять зачем нужны комментарии в документации. Что такого можно написать в комментариях к
CREATE TABLE
илиSELECT
, ради чего стоило бы в них рыться?pluzanov Автор
Возможно комментарии в документации реализованы не лучшим образом, но они есть. Для всех поддерживаемых версий (сейчас это с 9.5 по 12) внизу любой страницы документации есть раздел Submit correction. Заполняете форму и замечание после модерации приходит в список рассылки pgsql-docs. Там замечание обязательно рассматривают и если решат, что нужно внести изменения — вносят.
Да, списки рассылки не самый современный инструмент совместной работы, но проект postgresql пользуется именно им.
pluzanov Автор
На мой взгляд и прежний вариант был далек от идеала. По крайней мере, когда я первый раз увидел форматирование функций в виде таблиц мне это показалось очень неудобным. Потом привык.
Нынешний вариант не выглядит явным улучшением. Да, проще конвертировать в PDF, но к читаемости вопросы есть. Попробуем с этим поработать.
А вообще приятно, что несколько первых комментариев именно по документации. Это к извечной шутке о том, «кто её читать будет». Читают, и это здорово!
vazir
Еще как читаем. От качества документации напрямую зависит популярность проекта, у PG она на высоком уровне. Но глядя на изменения — таблица — это четкое структурирование, что, зачем, куда, пример. А новинка, 10х по времени на понимание где якорь. Про комменты: в основном люди туда пишут примеры. Смотрите тот же PHP, MYSQL, Python. И примеры это очень важно. Накопление базы вменяемых примеров — это годы… И желательно пропустить через рецензирование. Текущая схема «аля комментирования» от слова — не работоспособна (для масс).
pluzanov Автор
Согласен, база примеров (именно вменяемых) была бы очень полезна.