В этом уроке мы выходим за пределы одной базы. Сначала разберём, как PostgreSQL читает и пишет данные из чужих источников через механизм FDW (Foreign Data Wrapper), не копируя их к себе. Потом посмотрим на расширения: что это вообще такое, как они доустанавливают возможности в живую базу одной командой, и какие из них стоит знать каждому. В конце поговорим про то, где учиться дальше и как держать руку на пульсе экосистемы postgresql в 2026 году, включая сертификацию Postgres Professional.

Как это работает
FDW - это реализация стандарта SQL/MED (Management of External Data). Идея простая: вы описываете внешний источник как обычную таблицу, а драйвер-обёртка переводит запросы туда и обратно. Для вашего SELECT внешняя таблица выглядит почти как родная, но физически данные лежат в другой СУБД, в файле или за сетью. Это удобно для интеграции: не нужен ночной импорт, данные всегда свежие.
Цепочка объектов выстраивается так. Сначала ставится обёртка через CREATE EXTENSION postgres_fdw. Затем создаётся сервер (CREATE SERVER) - это описание, куда подключаться. Дальше идёт сопоставление пользователей (CREATE USER MAPPING) - кто и под каким логином ходит на удалённую сторону. И наконец сами внешние таблицы (CREATE FOREIGN TABLE) либо целый IMPORT FOREIGN SCHEMA, который вытянет описания таблиц автоматически.
Важная вещь про производительность - pushdown. Умный wrapper старается отправить на удалённую сторону как можно больше работы: фильтры WHERE, соединения, агрегаты, сортировку. Тогда по сети вернётся только результат, а не весь объём. Проверять, что именно ушло на удалённый сервер, надо через explain analyze - в плане видно строки Remote SQL.
Теперь расширения. Ядро postgresql намеренно держат компактным, а почти всё дополнительное оформляют как extension - это упакованный набор функций, типов данных, операторов и индексных методов, который подключается к конкретной базе командой CREATE EXTENSION. Расширение живёт внутри базы, а не всего кластера, поэтому ставить его надо в каждую нужную базу отдельно. Список доступных к установке смотрят в представлении pg_available_extensions, уже установленные - в pg_extension.
SQL и примеры
Поднимем связь с удалённым сервером, где лежит копия демобазы Авиаперевозки, и подтянем оттуда таблицу рейсов.
Код: Выделить всё
CREATE EXTENSION IF NOT EXISTS postgres_fdw;
CREATE SERVER air_remote
FOREIGN DATA WRAPPER postgres_fdw
OPTIONS (host '10.0.0.5', port '5432', dbname 'demo');
CREATE USER MAPPING FOR current_user
SERVER air_remote
OPTIONS (user 'reader', password 'secret');
Код: Выделить всё
CREATE SCHEMA remote_air;
IMPORT FOREIGN SCHEMA bookings
LIMIT TO (flights, airports, ticket_flights)
FROM SERVER air_remote
INTO remote_air;
Код: Выделить всё
SELECT a.airport_name, count(*) AS departures
FROM remote_air.flights f
JOIN remote_air.airports a ON a.airport_code = f.departure_airport
GROUP BY a.airport_name
ORDER BY departures DESC
LIMIT 10;
Код: Выделить всё
EXPLAIN (ANALYZE, VERBOSE)
SELECT flight_no, scheduled_departure
FROM remote_air.flights
WHERE status = 'Departed';
Теперь расширения. Поставим несколько популярных и посмотрим, как они помогают:
Код: Выделить всё
CREATE EXTENSION IF NOT EXISTS pg_trgm;
CREATE EXTENSION IF NOT EXISTS pg_stat_statements;
CREATE EXTENSION IF NOT EXISTS hstore;
Код: Выделить всё
SELECT city, similarity(city, 'Moskva') AS sim
FROM bookings.airports
WHERE city % 'Moskva'
ORDER BY sim DESC;
Код: Выделить всё
SELECT query, calls, round(total_exec_time::numeric, 1) AS total_ms
FROM pg_stat_statements
ORDER BY total_exec_time DESC
LIMIT 5;
Частые грабли
- Думают, что CREATE EXTENSION ставит расширение на весь кластер. Нет - только в текущую базу. Подключились к новой базе, повторили команду.
- Файлы расширения должны лежать на диске сервера заранее (пакет вроде postgresql-15-postgis или contrib). CREATE EXTENSION не качает их из интернета, а лишь регистрирует уже установленное.
- pg_stat_statements и подобные библиотеки молча не заработают без shared_preload_libraries и рестарта. Проверяйте SHOW shared_preload_libraries.
- С postgres_fdw легко получить тормоза: если pushdown не сработал, через сеть едет вся таблица. Всегда смотрите explain analyze и строку Remote SQL.
- use_remote_estimate по умолчанию выключен - планировщик гадает о размере удалённых таблиц. Для тяжёлых FDW-запросов включайте его на сервере или таблице.
- Хранение пароля в USER MAPPING открытым текстом - риск. Лучше отдельная роль только на чтение и ограниченные права на удалённой стороне.
- Версию расширения после обновления кластера надо поднимать вручную: ALTER EXTENSION ... UPDATE, иначе остаётесь на старом наборе функций.
- Шаг 1. В psql выполните CREATE EXTENSION pg_trgm; и проверьте установку запросом к pg_extension.
- Шаг 2. Создайте GIN-индекс на bookings.airports по столбцу city с классом операторов gin_trgm_ops.
- Шаг 3. Сделайте поиск похожих городов через оператор % и оцените план через EXPLAIN - используется ли индекс.
- Шаг 4. Установите pg_stat_statements (добавьте в shared_preload_libraries, перезапустите сервер, затем CREATE EXTENSION).
- Шаг 5. Прогоните несколько SELECT по bookings и найдите их в pg_stat_statements, отсортировав по mean_exec_time.
- Шаг 6. Посмотрите pg_available_extensions и выпишите три незнакомых расширения, прочитав их короткое описание в столбце comment.
- Шаг 7. (по желанию) Поднимите второй кластер локально, настройте postgres_fdw на него и сравните планы с use_remote_estimate on и off.
- Чем стандарт SQL/MED и FDW отличаются от обычного импорта данных, и в чём плюс работы с внешними таблицами?
- Какие четыре объекта нужно создать, чтобы прочитать таблицу через postgres_fdw, и за что отвечает каждый?
- Что такое pushdown и как по плану explain analyze понять, что фильтр ушёл на удалённый сервер?
- Почему CREATE EXTENSION надо повторять в каждой базе, и где смотреть список доступных и установленных расширений?
- Почему pg_stat_statements не заработает после одного CREATE EXTENSION, и что для него нужно настроить?
- Где сегодня учиться PostgreSQL дальше и какие шаги к сертификации Postgres Professional вы бы наметили?