Postgres выпускает потрясающую новую функцию

BBetter Stack
컴퓨터/소프트웨어AI/미래기술

스크립트

00:00:00Итак, оказывается, все те разработчики, которые твердили: «Брат, просто используй Postgres для всего», — правы
00:00:04ещё больше с выходом новой версии Postgres 19, в которую добавили нативную поддержку графовых запросов.
00:00:10И это действительно крутая функция. Поэтому в сегодняшнем видео я хочу рассказать обо всех главных возможностях
00:00:16Postgres 19, а также подробнее рассмотреть именно графовые запросы, потому что, как мне кажется, они
00:00:21могут кардинально изменить подход к проектированию запросов и использованию Postgres.
00:00:30Итак, первая новинка называется on conflict do select. Если вы хотите вставить строку только в том случае, если она
00:00:35ещё не существует, и в любом случае вернуть эту строку в качестве результата, обычно для этого требуются
00:00:40два запроса: insert и select, что является очень распространенным сценарием. Вот в примере
00:00:45мы говорим, что собираемся выполнить вставку в таблицу users (email и name), передаем значения, а затем в
00:00:50конце указываем on conflict для email do nothing returning star. Команда do nothing ничего не возвращает, если строка
00:00:56уже существует, поэтому приходится делать дополнительный select, но вместе эти операции не атомарны. В 19-й версии это можно сделать
00:01:03одним запросом. Insert в таблицу users с указанием email и name, после чего пишем on conflict email do select
00:01:11returning star. А если вы хотите внести изменения в рамках того же запроса, можно написать insert в users, снова передать
00:01:16значения, а для конфликта по email указать do select for update returning id и name. И поскольку это единый
00:01:23оператор, он атомарен: вы либо вставляете данные, либо получаете их выборку каждый раз. Учитывая распространенность задачи,
00:01:29это будет очень полезно. Следующая тема — графы, но если вам нравится это видео,
00:01:34почему бы не подписаться на Better Stack, чтобы быть в курсе последних технологических новинок? Как я уже говорил,
00:01:39на мой взгляд, это главная фича. Допустим, у вас есть стандартная схема для магазина: клиенты,
00:01:44заказы и продукты, а также две связующие таблицы, которые объединяют всё это вместе, и вы хотите узнать, какой именно
00:01:50продукт купил конкретный покупатель. В SQL это цепочка соединений по всем пяти таблицам, и здесь это ещё
00:01:56куда ни шло, но для более сложных связей всё быстро превращается в жуткое зрелище. Что ж, теперь мы
00:02:02можем делать выборку по всем этим данным как по графу, так что громоздкий синтаксис join заменяется новым графовым синтаксисом.
00:02:08И особенно заметную пользу это принесет при работе со сложными соединениями. Итак, мы находимся в нашем просмотрщике базы данных
00:02:14и видим все таблицы: продукты, заказы, события,
00:02:20а также клиентов и промежуточные таблицы для связи всех этих данных: элементы заказов
00:02:25и заказы клиентов. Давайте попробуем выполнить запрос ко всем этим таблицам. Допустим,
00:02:30у меня есть пользователь по имени Алиса, и я хочу узнать всё, что она заказала. Чтобы сделать это,
00:02:35мне пришлось бы перебирать множество различных операторов join, чтобы связать все эти таблицы. Поэтому я запускаю запрос,
00:02:41содержащий четыре отдельных оператора соединения, и хотя написать его не сказать чтобы очень сложно,
00:02:46выглядит он крайне громоздко. Запустив его, мы видим всё, что заказала Алиса:
00:02:51механическую клавиатуру и эргономичную мышь. Но теперь мы можем использовать графовый синтаксис, чтобы кардинально упростить
00:02:57эту задачу. Мы заменим всё это новым графовым синтаксисом и выполним запрос снова —
00:03:03как видите, результат тот же самый. А если выстроить всё в ряд, код становится намного понятнее:
00:03:07мы просто переходим от клиентов к заказам клиентов, затем к заказам, элементам заказов и продуктам.
00:03:13Таким образом, можно просто следовать этому простому пути для обхода всего графа, что, на мой взгляд, гораздо легче
00:03:19для восприятия. Если вы хотите выбрать несколько колонок, это тоже возможно:
00:03:23вверху остается тот же графовый запрос, а внизу мы можем перечислить нужные колонки
00:03:27и получить результаты внизу при выполнении. Конечно, ничто из этого не заработает,
00:03:32пока вы предварительно не создадите сам граф. Запрос, который я использовал для генерации графа, выглядит так:
00:03:37мы пишем create property graph, даем ему имя my shop и затем
00:03:42определяем таблицы вершин (vertex tables), которыми будут клиенты, заказы и продукты — то есть сущности,
00:03:47непосредственно хранящие данные. Затем мы указываем таблицы ребер (edge tables), которые создают связи
00:03:52— в нашем случае это промежуточные таблицы заказов клиентов и элементов заказов.
00:03:57Синтаксис для этого предельно прост: для заказов клиентов источником являются клиенты, а назначением — заказы,
00:04:02а для элементов заказов источником являются заказы, а назначением — продукты. Имея это в виду,
00:04:08Postgres теперь будет знать, как определены эти связи каждый раз, когда мы выполняем графовый запрос.
00:04:14Для работы функции нужно создать граф, но при этом не создаются новые таблицы или что-то подобное:
00:04:19вы просто ссылаетесь на пять уже имеющихся таблиц, где три таблицы с данными становятся
00:04:23вершинами, а две соединительные таблицы — ребрами. Это работает во многом как представление (view), поэтому ваша прежняя схема
00:04:29остается абсолютно неизменной, вы просто получаете дополнительный функционал поверх неё. Итак, здесь мы
00:04:35пишем create property graph, называем его my shop и описываем механику работы этих связей,
00:04:40выполняя всю подготовительную работу для графа, благодаря чему сами запросы получаются намного компактнее
00:04:45по сравнению с эквивалентным синтаксисом join. Заменяет ли это Neo4j? Что ж, если вам нужна графовая база данных
00:04:52ради специфического хранения графов и производительности обхода, то нет, специализированная графовая
00:04:58база данных по-прежнему останется лучшим выбором. Но если вам это нужно потому, что писать соединения из 10 таблиц
00:05:03в SQL утомительно и некрасиво, то вы определенно выиграете, и в сравнении это будет выглядеть гораздо приятнее.
00:05:09Третья новая функция — repack, и она предназначена для возврата дискового пространства. Postgres
00:05:15никогда не обновляет строки на месте: он записывает новую версию и оставляет старую позади, а vacuum лишь
00:05:21помечает это устаревшее пространство как пригодное для повторного использования, поэтому использование диска фактически не уменьшается. Repack перезаписывает всю
00:05:27таблицу в свежий файл без какого-либо расточительно расходуемого пространства, и именно это возвращает память
00:05:33операционной системе. Вообще-то сделать это можно было и раньше с помощью vacuum full, но такая команда блокирует таблицу
00:05:38на время всей перезаписи, поэтому для чего-то масштабного её никогда не запускают.
00:05:42Именно поэтому люди устанавливали сторонние расширения вроде pg_repack, но теперь эта возможность встроена прямо в Postgres:
00:05:49используйте ключевое слово concurrently, и таблица останется доступной для чтения и записи во время работы repack.
00:05:54Однако здесь нужно учитывать один момент: вам потребуется достаточно свободного места на диске для второй копии таблицы
00:06:00и всех ее индексов, то есть свободное пространство необходимо именно для того, чтобы освободить место.
00:06:06Так что это не полноценная замена pg_repack, но для обычной таблицы задачу она решает без расширений.
00:06:11А теперь быстренько пройдемся по остальным функциям релиза 19. Первая — подсказки для оптимизатора (query hints).
00:06:17Postgres сам решает, как именно выполнять ваш запрос, и со временем его мнение может измениться, поэтому запрос, работавший отлично целый год,
00:06:22вдруг начинает тормозить, хотя в коде ничего не менялось. Новый модуль под названием pg_plan_advice позволяет захватить план выполнения, пока он
00:06:28еще быстрый, и зафиксировать его, чтобы он всегда оставался таковым. JIT-компиляция теперь по умолчанию отключена: Postgres компилирует сложные запросы
00:06:36в машинный код, но решал, стоит ли это делать, на основе оценки стоимости планировщика, а в примечаниях к релизу
00:06:41указано, что эта оценка была ненадежной, поэтому JIT срабатывала на запросах, которым на самом деле
00:06:46это было не нужно. Кроме того, vacuum теперь может очищать индексы с помощью нескольких параллельных воркеров,
00:06:52что сокращает время обслуживания большой таблицы, правда, эту функцию нужно включать вручную. Знаете, когда вы добавляете колонку,
00:06:58чтобы сделать select, а потом приходится добавлять ту же колонку в group by? Теперь база делает это за вас.
00:07:03А ключевое слово copy теперь умеет экспортировать данные прямо в JSON, так что если вы выгружали CSV и конвертировали его
00:07:09потом, можете прекратить этим заниматься. Итак, бета-версия Postgres 19 вышла в июле, а финальный релиз
00:07:15ожидается примерно в сентябре или октябре, так что если вы используете что-то более старое, стоит загрузить бета-версию
00:07:21и протестировать ее прямо сейчас. А если вы хотите узнать больше о Postgres, вы можете ознакомиться
00:07:25с обзором pg_durable, который добавляет надежные рабочие процессы прямо внутрь Postgres. С вами был Уоррен из
00:07:31Better Stack, спасибо за просмотр, и до встречи в следующем выпуске.

핵심 요약

Релиз Postgres 19 внедряет нативные графовые запросы, атомарные операции on conflict do select и безопасную очистку диска через repack без блокировки таблиц.

하이라이트

  • Версия Postgres 19 добавляет нативную поддержку графовых запросов для упрощения сложных связей в базе данных.

  • Новый синтаксис on conflict do select объединяет вставку и выборку строк в единую атомарную операцию.

  • Встроенная команда repack с ключевым словом concurrently возвращает дисковое пространство без блокировки таблиц.

  • Модуль pg_plan_advice фиксирует план выполнения запросов для предотвращения деградации производительности.

  • Команда copy теперь поддерживает прямой экспорт данных в формат JSON.

타임라인

Нативная поддержка графовых запросов

  • Версия Postgres 19 включает встроенные графовые запросы.
  • Новый функционал заменяет громоздкие цепочки операторов join простым синтаксисом обхода.
  • Граф создается с помощью инструкции create property graph без изменения исходной схемы таблиц.

Сложные связи между клиентами, заказами и продуктами традиционно требуют объединения пяти и более таблиц через join. Графовый синтаксис позволяет выстроить этот путь линейно. Таблицы данных выступают в роли вершин, а промежуточные таблицы связывают их в качестве ребер. Это работает аналогично представлению, сохраняя базовую структуру неизменной, но значительно упрощая чтение кода.

Атомарные операции on conflict и возвращение дискового пространства

  • Команда on conflict do select выполняет вставку и выборку данных в рамках одного атомарного запроса.
  • Функция repack перезаписывает таблицу в свежий файл и возвращает память операционной системе.
  • Ключевое слово concurrently позволяет выполнять repack без блокировки таблицы для чтения и записи.

Раньше для проверки существования строки и её возврата требовалось два раздельных запроса insert и select. Новый синтаксис делает эту операцию атомарной. Для очистки диска используется repack, заменяющий старый vacuum full. Благодаря фоновому выполнению таблица остается доступной, хотя для процесса требуется дополнительное свободное место под копию данных.

Дополнительные улучшения в Postgres 19

  • Модуль pg_plan_advice фиксирует стабильный план выполнения запросов.
  • JIT-компиляция по умолчанию отключена из-за ненадежной оценки стоимости планировщика.
  • Оператор copy получил встроенную возможность экспорта данных напрямую в JSON.

Релиз приносит множество точечных улучшений для оптимизации работы разработчиков. Появилась параллельная очистка индексов силами нескольких воркеров и автоматическое добавление колонок в group by при запросах. Бета-версия вышла в июле, а финальный релиз запланирован на осень.

커뮤니티 글

모든 글 보기