Transcript
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, спасибо за просмотр, и до встречи в следующем выпуске.