Обзор Foreign-Data Wrappers (FDW) в PostgreSQL
Для того, чтобы использовать функцию FDW, необходимо установить соответствующее расширение и выполнить такие команды, как CREATE FOREIGN TABLE, CREATE SERVER, а также CREATE USER MAPPING (более подробная информация представлена в официальном документе).
После установки соответствующих настроек во время обработки запроса для доступа к внешним таблицам вызываются функции, определенные в расширении.
Рис. 43 описывает работу инструмента.
- (1) Анализатор создает дерево запросов SQL.
- (2) Планировщик (или Исполнитель) поключается к удаленному серверу.
- (3)Если параметр use_remote_estimate включен (по умолчанию он выключен), планировщик выполняет команды EXPLAIN для оценки стоимости каждого пути.
- (4) Планировщик создает из дерева планов обычный текстовый SQL-оператор, который внутренне называется deparesing.
- (5) Исполнитель отправляет текстовый SQL-запрос на удаленный сервер и получает результат.
Затем при необходимости исполнитель обрабатывает полученные данные.
Подробности описаны в последующих разделах.
Построение дерева запроса
Анализатор создает дерево запросов с использованием определений сторонних таблиц, которые хранятся в схемах pg_catalog.pg_class и pg_catalog.pg_foreign_table, используя команды CREATE FOREIGN TABLE и IMPORT FOREIGN SCHEMA.
Подключение к удаленному серверу
Чтобы подключиться к удаленному серверу, планировщик (или исполнитель) использует определенную библиотеку. Например, чтобы подключиться к удаленному серверу PostgreSQL postgres_fdw использует библиотеку libpq. Чтобы подключиться к серверу MySQL расширение mysql_fdw использует библеотеку libmysqlclient.
Параметры соединения, такие как имя пользователя, IP-адрес сервера и номер порта, хранятся в каталогах pg_catalog.pg_user_mapping и pg_catalog.pg_foreign_server.
Создание дерева планов с помощью команд EXPLAIN (по желанию)
FDW поддерживает возможность получения статистики сторонних таблиц для оценки дерева планов. Некоторые расширения FDW, такие как postgres_fdw, mysql_fdw, tds_fdw и jdbc2_fdw, используют эту статистику.
Если опция use_remote_estimate включена с помощью команды ALTER SERVER, планировщик запрашивает стоимость планов на удаленном сервере с помощью команды EXPLAIN. В противном случае по умолчанию используются встроенные константы.
localdb=#ALTERSERVER remote_server_nameOPTIONS(use_remote_estimate'on');
Несмотря на то, что некоторые расширения используют значения команды EXPLAIN, только postgres_fdw может отражать результаты команд EXPLAIN, поскольку команда EXPLAIN в PostgreSQL возвращает как начальные, так и общие затраты.
Результаты команды EXPLAIN не могут быть использованы другими расширениями FDW. Например, команда EXPLAIN в mysql возвращает только предполагаемое количество строк. Однако планировщику PostgreSQL для оценки затрат требуется гораздо больше информации (смотрите раздел 3).
Deparesing
Чтобы сгенерировать дерево планов, планировщик создает обычный текстовый SQL-оператор. Например, на рис. 4.3 показано дерево плана оператора SELECT.
localdb=# SELECT * FROM tbl_a AS a WHERE a.id < 10;
На рис. 4.3 показано, что узел ForeignScan, связанный с деревом планов PlannedStmt, хранит обычный текст SELECT. Здесь postgres_fdw воссоздает обычный текст SELECT из дерева запросов, которое было создано в результате разбора и анализа, что в PostgreSQL называется deparesing.
Использование mysql_fdw воссоздает текст SELECT для MySQL из дерева запросов. Использование redis_fdw или rw_redis_fdw создает команду SELECT.
Отправка выражений SQL и получение результата
После deparesing исполнитель отправляет депарсированные SQL-запросы на удаленный сервер и получает результат.
Метод отправки SQL-запросов на удаленный сервер зависит от разработчика каждого расширения. Например, mysql_fdw отправляет SQL-запросы без использования транзакции. Типичная последовательность SQL-запросов, используемая для выполнения запроса SELECT в mysql_fdw показана ниже (рис. 44).
- (5-1) Установка SQL_MODE на ‘ANSI_QUOTES’;
- (5-2) Отправка выражения SELECT на удаленный сервер;
- (5-3) Получение результата от удаленного сервера.
В данном случае mysql_fdw преобразует результат в данные, доступные для чтения PostgreSQL.
Все расширения FDW реализуют функцию, преобразуеющую результат в данные, доступные для чтения PostgreSQL.
Журнал удаленного сервера
mysql>SELECT command_type,argument FROM mysql.general_log;+--------------+-----------------------------------------------------------------------+|command_type|argument|+--------------+-----------------------------------------------------------------------+... snip ...|Query|SET sql_mode='ANSI_QUOTES'||Prepare|SELECT`id`,`data`FROM`localdb`.`tbl_a`WHERE((`id`<10))||Close stmt||+--------------+-----------------------------------------------------------------------+
В postgres_fdw последовательность команд SQL гораздо сложнее. Типичная последовательность операторов SQL для выполнения запроса SELECT в postgres_fdw показана ниже (рис. 45).
- (5-1) Запуск удаленной транзакции.
Уровень изоляции удаленной транзакции по умолчанию - REPEATABLE READ; если уровень изоляции локальной транзакции установлен на SERIALIZABLE, удаленная транзакция также устанавливается на SERIALIZABLE.
-
(5-2)-(5-4) DECLARE CURSOR.
- (5-5) Выполнение команд FETCH для получения результата.
По умолчанию командой FETCH извлекается 100 строк..
- (5-6) Получение результата от удаленного сервера.
- (5-7) Закрытие курсора.
- (5-8) Выполнение удаленной транзакции
Журнал удаленного сервера
LOG: statement: START TRANSACTION ISOLATION LEVEL REPEATABLE READLOG: parse<unnamed>:DECLARE c1 CURSOR FOR SELECT id, data FROM public.tbl_aWHERE((id<10))LOG: bind<unnamed>:DECLARE c1 CURSOR FOR SELECT id, data FROM public.tbl_aWHERE((id<10))LOG: execute<unnamed>:DECLARE c1 CURSOR FOR SELECT id, data FROM public.tbl_aWHERE((id<10))LOG: statement: FETCH100FROM c1LOG: statement: CLOSE c1LOG:statement:COMMITTRANSACTION
.
Описание того, почему уровнем изоляции удаленной транзакции является REPEATABLE READ, Вы найдете в официальном документе.
Примечание:
Удаленная транзакция использует уровень изоляции SERIALIZABLE, если локальная транзакция имеет уровень изоляции SERIALIZABLE; в противном случае она использует уровень изоляции REPEATABLE READ.
В режиме REPEATABLE READ видны только те данные, которые были зафиксированы до начала транзакции, но не видны незафиксированные данные и изменения, произведённые другими транзакциями в процессе выполнения данной транзакции. Однако запрос будет видеть эффекты предыдущих изменений в своей транзакции, несмотря на то, что они не зафиксированы.
Уровень SERIALIZABLE обеспечивает самую строгую изоляцию транзакций. На этом уровне моделируется последовательное выполнение всех зафиксированных транзакций, как если бы транзакции выполнялись одна за другой, последовательно, а не параллельно. Однако, как и на уровне REPEATABLE READ, на этом уровне приложения должны быть готовы повторять транзакции из-за сбоев сериализации. Фактически этот режим изоляции работает так же, как и Repeatable Read, только он дополнительно отслеживает условия, при которых результат параллельно выполняемых сериализуемых транзакций может не согласовываться с результатом этих же транзакций, выполняемых по очереди.






