Что заморозили на feature freeze
8-го апреля закончился комитфест 2018–03. Те патчи, которые не закомичены на нем (и на 3 предыдущих комитфестах) уже не попадут в релиз PostgreSQL 11: произошла заморозка функциональности (feature freeze). Время подводить итоги.
Главные новости последнего комитфеста (и версии 11 соответственно):
- увесистый набор патчей для секционирования.
- JIT-компиляции посвящен только один патч, но это шаг в направлении, которое в будущем наверняка будет развиваться интенсивно.
- «покрывающие» индексы (INCLUDE-индексы). Это тема уже активно обсуждается и продолжается в разработках.
- Серия патчей в группе процедурных языков. Они важны в том числе для совместимости со стандартами SQL и миграции с Oracle.
- Интересные, но не столь резонансные патчи.
Начнем в произвольном порядке.
JIT-компиляция
JIT compiling expressions & tuple deforming
Без JIT выполнение запроса представляет собой интерпретацию плана выполнения. С JIT, то есть с компиляцией just-in-time, или «на лету», отдельные части запроса компилируются, и за счет этого запрос выполняется быстрее. Характерный пример — JIT-компиляция выражений в SQL-запросах. В этом патче, автор которого Андрес Фройнд из EnterpriseDB, есть и психологическая составляющая: для JIT теперь задействован компилятор LLVM — его называют даже «компиляторной инфраструктурой». Он часто используется именно для JIT, он удобен, позволяет встраивать функции в код (inline), оптимизирует код и он достаточно универсален с точки зрения целевых платформ. При деформинге записей (разворачивании строк в памяти) тоже используется LLVM, и это тоже повышает производительность.
INCLUDE-индексы
Covering B-tree indexes (aka INCLUDE)
INCLUDE-индексы — большой патч российского просхождения, его начала разратывать еще 2 года назад Анастасия Лубенникова и продолжили Александр Коротков и Федор Сигаев (все они из Postgres Professional — ну да, мы неравнодушны к отечественному вкладу в комьюнити). INCLUDE-индексы иногда называют покрывающими индексами, но, строго говоря, покрывающим индексом для конкретного запроса называется индекс, который содержит все необходимые в запросе столбцы таблицы. А смысл INCLUDE-индексов в том, чтобы индекс мог стать покрывающим не за счет включения в него дополнительных столбцов, а за счет хранения дополнительной информации (неиндексированных значений). Например, таким образом можно расширить уникальный индекс, который останется при этом уникальным.
CREATE UNIQUE INDEX newidx ON newt USING btree (c1, c2) INCLUDING (c3, c4);
Они позволяют увеличить производительность, так как index only scan обычно намного быстрее, а по сравнению с другими способами перейти к index only scan они менее громоздки: можно обойтись одним индексом там, где нужно было 2 и больше, а значит меньше времени и ресурсов тратится на обновление индексов при вставке и обновлении. Патч Covering B-tree indexes (aka INCLUDE) — это тоже первый шаг потому, что дальше последует поддержка покрывающих индексов для других их видов: уже начата, например, работа по поддержке GiST.
Примеры есть в блоге Александра Алексеева (Postgres Pro) и блоге Алексея Лесовского (Data Egret).
Новое в процедурных языках (по Айзентрауту)
SQL procedures,
Transaction control in procedures,
PL/pgSQL nested CALL with transactions,
SET TRANSACTION in PL/pgSQL,
INOUT parameters in procedures
Эти патчи авторства Питера Айзентраута из 2ndQuadrant делают процедурные языки PostgreSQL процедурными в буквальном смысле: кроме хранимых функций теперь будут и полноценные хранимые процедуры. Патч SQL procedures принят в конце прошлого года. С тех пор интерпретатору стал понятен синтаксис с командами CREATE/ALTER/DROP PROCEDURE, вызов процедуры CALL, а также ROUTINE. В январе добавлено самое ценное — управление транзакциями в процедурах: Transaction control in procedures. А вот этот патчINOUT
позволяет создавать процедуры таким образом:
CREATE PROCEDURE foo(INOUT a int)
LANGUAGE plpgsql
AS $$
begin
SELECT 1 into a;
end;$$;
Раньше SET TRANSACTION возможно было только в SQL, но не в plpgsql. С патчем это уже возможно, и это тоже шаг навстречу мигрирующим с Oracle. Также возможны теперь и вложенные вызовы функций (и DO) с транзакциями.
Секционирование
Над этой большой серией патчей работала команда NTT — Амит Лангот (Amit Langote) и другие. Еще в ноябре прошлого года был принят патч, добавляющий секционирование по хешу. Теперь все основные виды секционирования в PostgreSQL есть.
Но самая важная новость другая: серия патчей дает возможность создавать уникальные индексы, PRIMARY KEY глобально на всей секционированной таблице (об этом можно найти некоторую информацию например здесь: unique indexes on partitioned tables. Следовательно можно создавать и таблицы, ссылающиеся на секционированную таблицу: foreign keys and partitioned tables. Можно будет обновлять секционированную таблицу, не думая о том, останется ли запись в той же секции (версия 10 выдала бы ошибку): UPDATE of partition key. Появился ON CONFLICT DO UPDATE for partitioned tables.
То есть обращаться с секционированной таблицей можно почти как с обычной. Почти — потому, что возможности будут работать только если в уникальный индекс входят поля, составляющие ключ разбиения (partition key). Но это огромный шаг в любом случае.
Что касается Add support for tuple routing to foreign partitions, то этот патч, который автоматически направляет вставляемые записи во внешние секции, важен в том числе для тех, кто будет создавать системы с шардингом на базе новых возможностей секционирования.
Важнейшее умение оптимизатора — эффективно исключать из плана секции, в которых заведомо нет данных (патч faster partition pruning in planner). В случае, когда секций много (а в реальных проектах встречаются тысячи, а то и десятки тысяч), исключение секций (pruning) может серьезно снизить время исполнения запроса. Исключать нежелательных можно будет и на этапе исполнения (патч Runtime Partition Pruning), когда заранее не известно условие попадания в ту или иную секцию. Так случается, например, в запросах с подзапросами.
Partition-wise join for declarative partitioned tables представляет собой реализацию алгоритмов соединения двух секционированных таблиц. Соединение происходит отдельно по секциям, а потом собирается вместе. Во многих случаях это быстрее, чем соединять родительские таблицы. Аналогично при Partition-wise aggregation/grouping агрегирование охватывает сначала отдельные секции, потом результаты собирают.
Среди удобств появится секция по умолчанию (Default Partition for Range), куда попадали бы все записи, выходящие за границы заданных секций, чтобы не останавливаться каждый раз из-за ошибки. Автоматическое создание секций под данные, диапазон которых заранее не известен, пока даже не планируется (это умеет делать расширение pg_pathman).
JSON (B)
В этом направлении усилия делаются уже более 2 лет командой разработчиков Postgres Pro. Поскольку патчи увесистые и затрагивают многие механизмы postgres, принимаются сообществом они неторопливо. В PostgreSQL 11 вошли 3 патча:
Jsonb transform for pl/perl и
Jsonb transform for pl/python Антона Быкова (эффективные трансформации бинарных JSON при передаче их в функции Perl и Python) и
Cast jsonb to numeric, int, float, bool Анастасии Лубенниковой (преобразование типов). Но такие ключевые патчи как
SQL/JSON support in PostgreSQL, или
SQL/JSON: jsonpath, или
SQL/JSON: functions
по-прежнему ждут. А ведь это поддержка стандарта SQL/JSON.
В контексте JSON можно упомянуть и патч Константина Книжника, полезные для сюръективных (surjective) функций работающих с JSON, например вида (info→>'name')., но может пригодиться и для других целей.
Параллельные Gather и сортировка при создании индексов B-tree
Gather speed-up более рационально работает с очередями в памяти, ускоряет запросы, особенно простые.
Parallel tuplesort (for parallel B-Tree index creation). Это еще январский патч — параллельная сортировка записей для индексов B-tree.
index-only count (*) for indexes supporting bitmap scans (А.Кузьменков, Postgres Professional) принят в конце прошлого года. Запросы вида SELECT (*)… WHERE …, где в выражении нужная для запроса информация содержится в индексах, можно теперь существенно ускорить.
VACUUM
Не слишком принципиальное изменение, но все же: теперь можно запускать VACUUM нескольких таблиц одной командой: Allow users to specify multiple tables in VACUUM commands. Патч принят еще в конце прошлого года. В то же время важнейшие патчи, касающиеся приоритетов вакуумизации различных таблиц, расписания вакуумирования пока ждут.
Логическая репликация
Она в ванильной PostgreSQL продвинулась не сильно. Появилась поддержка TRUNCATE: Logical decoding of TRUNCATE
Контрольные суммы
Verify Checksums during Basebackups. Теперь можно проверять контрольные суммы в процессе бэкапа (если контрольные суммы включены).
Вклад в версию 11 отечественных разработчиков существенный. Но это тема другого рассказа. А пока — спасибо всем разработчикам (и ревьюерам) грядущего релиза!
[фото автора. на фото заfreezeн герой фильма «Левиафан» — г. Кировск, Кольский п-ов.]