PostgreSQL 16: Часть 1 или Коммитфест 2022-07

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

PostgreSQL 16: Часть 1 или Коммитфест 2022-07


Август в релизном цикле PostgreSQL месяц особенный. Еще не вышла официально 15-я версия, но уже закончился первый коммитфест 16-й версии. И мы можем посмотреть на самые интересные изменения.


Собираем сервер из исходного кода и вперед!


\dconfig server_version

List of configuration parameters
   Parameter    |  Value  
----------------+---------
 server_version | 16devel

PostgreSQL 15


После заморозки кода 15-й версии не обошлось без потерь. Откатили следующие изменения:


Индексы BRIN не блокируют HOT-обновления
Оптимизация работы с вложенными транзакциями


PostgreSQL 16


В этот обзор попали следующие 14 изменений:


psql: \pset xheader_width
vacuumdb --schema и --exclude-schema
Новые возможности утилиты createuser
Сообщение журнала о контрольной точке дополнили номерами LSN самой точки и начала восстановления
pg_prepared_statements.result_types
auto_explain: параметр log_parameter_max_length
Необязательные псевдонимы для подзапросов во фразе FROM
REINDEX: синтаксис и не только
CREATE STATISTICS: необязательно указывать имя статистики
CREATE TABLE: атрибут STORAGE
У созданного при инициализации кластера пользователя нельзя отобрать полномочия суперпользователя
Триггеры на TRUNCATE для внешних таблиц
pg_read_file/pg_read_binary_file: новая вариация указания параметров
Собственные менеджеры ресурсов WAL



psql: \pset xheader_width
commit: a45388d6


Развернутый режим вывода результатов запросов (\x или \pset expanded) удобен когда данные всех столбцов не помещаются на экран. Но и в развернутом режиме данные длинных столбцов также могут не помещаться в окно терминала.


Для примера в окне терминала шириной в 72 символа выполним запрос:


\pset expanded on
\pset pager off

SELECT version(),
       length(version()) version_length;

-[ RECORD 1 ]--+--------------------------------------------------------
-------------------------------------------------
version        | PostgreSQL 16devel on x86_64-pc-linux-gnu, compiled by 
gcc (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0, 64-bit
version_length | 104

Значение функции version не помещается по ширине, поэтому переносится на следующую строку. С этим все нормально. Но вот строка заголовка записи форматируется по самому широкому столбцу и также переносится на следующую строку. И чем длиннее самый широкий столбец, тем больше места будет занимать строка заголовка записи. Это особенно неудобно, когда выводится несколько записей и у каждой записи заголовок занимает несколько строк. (Попробуйте выполнить в развернутом режиме запрос SELECT * FROM pg_proc;)


В 16-й версии в psql появился новый параметр форматирования строки заголовка развернутого режима.


\pset xheader_width

Expanded header width is 'full'.

Значение по умолчанию (full) соответствует поведению в предыдущих версиях. Другие возможные значения:


  • column ― заголовок записи обрезается до ширины первого столбца вывода;
  • page ― заголовок записи обрезается до ширины окна терминала;
  • число ― заголовок записи обрезается до указанного числа.

\pset xheader_width column

Expanded header width is 'column'.

SELECT version(),
       length(version()) version_length;

-[ RECORD 1 ]--+
version        | PostgreSQL 16devel on x86_64-pc-linux-gnu, compiled by 
gcc (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0, 64-bit
version_length | 104

Заголовок записи больше не расходует напрасно полезное место окна терминала.



vacuumdb --schema и --exclude-schema
commit: 7781f4e3


У vacuumdb новые параметры для очистки таблиц в указанных схемах (--schema) или таблиц, не принадлежащих указанным схемам (--exclude-schema).



Новые возможности утилиты createuser
commit: 08951a7c


Утилита createuser является оберткой над командой CREATE ROLE, но с ограниченным функционалом. Это изменение добавляет утилите ряд параметров, реализующих отсутствующие ранее возможности, а именно:


  • --valid-until для формирования фразы VALID UNTIL;
  • --bypassrls/--no-bypassrls для формирования атрибута BYPASSRLS/NOBYPASSRLS;
  • -m/--member для включения создаваемой роли в указанную роль;
  • -a/--admin для включения создаваемой роли в указанную роль с предложением WITH ADMIN OPTION.


Сообщение журнала о контрольной точке дополнили номерами LSN самой точки и начала восстановления
commit: 62c46eee


После завершения контрольной точки в WAL делается запись с номером LSN контрольной точки и номером LSN, откуда начинать восстановление в случае сбоя (redo LSN).


Для последней выполненной контрольной точки эти два номера LSN записываются в управляющий файл:


$ pg_controldata | egrep 'Latest.*location'

Latest checkpoint location:         1/1A3DEB20
Latest checkpoint's REDO location:  1/1A3DEAE8

А в 16-й версии их добавили в сообщение о завершении контрольной точки журнала сервера:


2022-08-02 12:15:17.961 MSK [198868] LOG:  checkpoint complete: wrote 0 buffers (0.0%); 0 WAL file(s) added, 0 removed, 0 recycled; write=0.001 s, sync=0.001 s, total=0.072 s; sync files=0, longest=0.000 s, average=0.000 s; distance=0 kB, estimate=418462 kB; lsn=1/1A3DEB20, redo lsn=1/1A3DEAE8

Стоит напомнить, что начиная с 15-й версии параметр log_checkpoints включен по умолчанию.



pg_prepared_statements.result_types
commit: 84ad713c, 6ffff0fd


В представление pg_prepared_statements добавили столбец result_types.


PREPARE get_booking (text) AS
SELECT * FROM bookings WHERE book_ref = $1;

SELECT * FROM pg_prepared_statements WHERE name = 'get_booking'\gx

-[ RECORD 1 ]---+-----------------------------------------------
name            | get_booking
statement       | PREPARE get_booking (text) AS                 +
                | SELECT * FROM bookings WHERE book_ref = $1;
prepare_time    | 2022-08-02 16:54:14.313221+03
parameter_types | {text}
result_types    | {character,"timestamp with time zone",numeric}
from_sql        | t
generic_plans   | 0
custom_plans    | 0

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



auto_explain: параметр log_parameter_max_length
commit: d4bfe412


Новый параметр расширения auto_explain.log_parameter_max_length выполняет ту же задачу, что и аналогичный log_parameter_max_length, а именно ― журналирует значения параметров запросов.


LOAD 'auto_explain';
SHOW auto_explain.log_parameter_max_length;

 auto_explain.log_parameter_max_length
---------------------------------------
 -1
(1 row)

Значение по умолчанию равно -1. Это говорит о том, что будут выводиться полные значения параметров. Значение 0 отключает вывод значений параметров, положительное число ограничивает вывод значений указанным количеством байт.


Настроим журналирование и сформируем параметризированный запрос командой EXECUTE… USING в анонимном блоке PL/pgSQL.


SET auto_explain.log_min_duration = 0;
SET auto_explain.log_nested_statements = 'on';
SET auto_explain.log_level = 'NOTICE';

DO $$BEGIN EXECUTE 'SELECT $1' USING 42; END;$$;

NOTICE:  duration: 0.003 ms  plan:
Query Text: SELECT $1
Query Parameters: $1 = '42'
Result  (cost=0.00..0.01 rows=1 width=4)
DO

В вывод добавилась строка Query Parameters, позволяющая узнать, с какими значениями выполнялся запрос в строке Query Text.



Необязательные псевдонимы для подзапросов во фразе FROM
commit: bcedd8f5


Для подзапросов во фразе FROM стандарт SQL требует наличия псевдонима:


15=# SELECT * FROM (SELECT 42 AS a);

ERROR:  subquery in FROM must have an alias
LINE 1: SELECT * FROM (SELECT 42 AS a);
                    ^
HINT:  For example, FROM (SELECT ...) [AS] foo.

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


В 16-й версии такие псевдонимы не обязательны и в PostgreSQL.


16=# SELECT * FROM (SELECT 42 AS a);

 a  
----
 42
(1 row)


REINDEX: синтаксис и не только
commit: 2cbc3c17


Варианты команды REINDEX DATABASE и REINDEX SYSTEM требовали указания базы данных. Но указать можно только текущую базу данных, что делает это требование излишним. В новой версии имя базы данных становится необязательным.


Кроме того, команда REINDEX DATABASE теперь переиндексирует только пользовательские индексы и пропускает индексы таблиц системного каталога. Прежнего поведения, а именно перестроения всех индексов базы данных, можно добиться выполнением двух команд REINDEX DATABASE и REINDEX SYSTEM.


Такое изменение обосновано тем, что до сих пор не было способа перестроить только пользовательские индексы во всей базе данных. К тому же перестроение системных индексов невозможно в режиме CONCURRENTLY, а в высоконагруженных системах может вызывать взаимоблокировки.



CREATE STATISTICS: необязательно указывать имя статистики
commit: 624aa2a1


Расширенная статистика ― отдельный объект в базе данных и нуждается в имени. Но почему бы не разрешить опускать имя при создании, доверив его формирование самой СУБД? Точно так же, как это возможно для индексов и ограничений целостности.


Сделали:


CREATE STATISTICS ON departure_airport, arrival_airport FROM flights;

\d flights

...
Statistics objects:
    "bookings.flights_departure_airport_arrival_airport_stat" ON departure_airport, arrival_airport FROM flights


CREATE TABLE: атрибут STORAGE
commit: 784cedda


Предположим, мы решили хранить изображения в базе данных. Создаем таблицу:


CREATE TABLE images (filename text, data bytea);
ALTER TABLE images ALTER COLUMN data SET STORAGE external;

Во второй команде меняем стратегию хранения TOAST на external, чтобы запретить сжатие данных. Ведь файлы изображений и так сжаты.


Вопрос в том, зачем это делать отдельной командой, а не сразу указать нужную стратегию в CREATE TABLE? Ответ простой: CREATE TABLE до 16-й версии не позволяет указывать атрибут STORAGE для столбцов, что и было исправлено:


CREATE TABLE images (filename text, data bytea STORAGE external);


У созданного при инициализации кластера пользователя нельзя отобрать полномочия суперпользователя
commit: e530be2c


Суперпользователь, созданный при инициализации кластера (pg_authid.oid=10), мог сам у себя отобрать атрибут SUPERUSER:


15=# ALTER ROLE postgres NOSUPERUSER;

(Если другого суперпользователя нет, то чтобы вернуть атрибут придется запускать сервер в однопользовательском режиме.)


В 16-й версии случайно лишиться суперпользовательских полномочий не получится:


16=# ALTER ROLE postgres NOSUPERUSER;

ERROR:  permission denied: bootstrap user must be superuser

Кстати, удалить суперпользователя, созданного при инициализации кластера было и раньше нельзя:


CREATE ROLE root LOGIN SUPERUSER;
\c - root

DROP ROLE postgres;

ERROR:  cannot drop role postgres because it is required by the database system

Общий вывод можно сделать такой. Начальный суперпользователь необходим для нормального функционирования сервера. Удалять или отнимать у него привилегии не нужно. В плане обеспечения дополнительной безопасности можно подумать о том, чтобы сделать эту роль групповой, забрав атрибут LOGIN.



Триггеры на TRUNCATE для внешних таблиц
commit: 3b00a944


Некоторые обертки сторонних данных поддерживают команду TRUNCATE. Этот патч добавляет возможность создавать триггер на TRUNCATE для внешних таблиц таких оберток.



pg_read_file/pg_read_binary_file: новая вариация указания параметров
commit: 283129e3


Спецификация функций pg_read_file и похожей pg_read_binary_file была такой:


pg_read_file ( filename text [, offset bigint, length bigint [, missing_ok boolean ]] ) → text

Предполагается, что для чтения файла целиком нужно не указывать параметры offset и length. Но тогда не получается задать missing_ok=true для игнорирования отсутствия файла.


В 16-й версии добавили еще один перегруженный вариант функций, что привело общую спецификацию к виду:


pg_read_file ( filename text [, offset bigint, length bigint ] [, missing_ok boolean ] ) → text

Теперь можно указать только имя файла и игнорировать его отсутствие.



Собственные менеджеры ресурсов WAL
commit: 5c279a6d


Особую роль патча подчеркивает мой коллега, Егор Рогов. Ему и слово.


Одна из проблем, стоящих перед разработчиками табличных и индексных методов доступа — невозможность формировать журнальные записи специфического вида. Существует механизм унифицированных журнальных записей, который сбрасывает в WAL “разницу” между старым и новым состояниями страницы (им пользуется, например, расширение rum), но он не слишком эффективен и не поддерживает логическую репликацию.


В версии 16 расширения смогут создавать собственные менеджеры ресурсов и, соответственно, журнальные записи собственного формата. Обратная сторона медали в том, что восстановление экземпляра после сбоя становится зависимым от стороннего расширения.


С точки зрения пользователя патч ничего не меняет, но это еще один важный шаг на пути к появлению новых методов доступа.




На этом пока всё. Ждем следующего сентябрьского коммитфеста и, конечно же, официального выхода 15-й версии.

Источник: https://habr.com/ru/company/postgrespro/blog/681164/

Интересные статьи

Интересные статьи

Основой любого приложения является его главный поток. На нем происходят все самые важные вещи: создаются другие потоки, меняется UI. Важнейшей его частью является цикл. Так как поток главный, то и его...
pfBlockerNG? Что это? Далеко немногие используют функционал pfSense на полную - а ведь данный пакет является по сути opensource решением близким к Cisco Firepower Security Intelligence и OpenDNS, ну ...
Здравствуйте, товарищи! Прошло чуть больше полугода после выхода предыдущей статьи о Windows 10 Sophia Script — скрипте, который за прошедшие годы стал самым крупным (а и...
Прим. перев.: в конце января Percona опубликовала результаты своего небольшого сравнения производительности для СУБД PostgreSQL, запущенной на x86- и ARM-инстансах AWS. Результаты получил...
Одним из самых популярных процессоров уходящего десятилетия стал Intel Core i7-2600K. Дизайн был революционным, так как он предлагал значительный скачок в производительности и эффективности о...