Интероперабельность PostgreSQL и YDB
Важно
Поддержка синтаксиса PostgreSQL в YDB находится в разработке. Использовать её в production окружениях не рекомендуется. Запросы в PostgreSQL могут исполняться до нескольких раз медленнее по сравнению с аналогичными запросами на YQL.
Основной сценарий, который можно тестировать — выполнение аналитических запросов к хранимым в YDB данным.
Поддержка исполнения запросов в YDB в синтаксисе PostgreSQL реализована с помощью слоя совместимости:
- Программа отправляет запросы в YDB, где их обрабатывает компонент под названием pgwire. Pgwire реализует сетевой протокол PostgreSQL и передает команды в query processor.
- Query processor транслирует PostgreSQL запросы в YQL AST.
- После обработки запросов результаты собираются и отправляются обратно в программу, отправившую запрос, по сетевому протоколу PostgreSQL. При обработке запроса он может распараллеливаться и исполняться на произвольном количестве узлов YDB.
Графически работу PostgreSQL совместимости можно представить так:

Такая архитектура интеграции с PostgreSQL позволяет выполнять запросы на PostgreSQL над YDB типами данных и наоборот, выполнять YQL-запросы над типами данных PostgreSQL, обеспечивая интероперабельность работы с данными.
Проиллюстрируем это с помощью следующего сценария:
- 
Создадим таблицу YDB с помощью YQL-синтаксиса CREATE TABLE `test_table`(col INT, PRIMARY KEY(col));
- 
Добавим туда тестовые данные INSERT INTO test_table(col) VALUES(1)
- 
Прочитаем эти данные с помощью PostgreSQL-синтаксиса psql -h <ydb_address> -d <database_name> -U <user_name> -c "SELECT * FROM test_table" col --- 1 (1 row)Где: - <ydb_address>- адрес кластера YDB, к которому выполняется подключение.
- <database_name>- название базы данных в кластере. Может быть сложным именем, например,- mycluster/tenant1/database.
- <user_name>- логин пользователя.
 
Соответствие типов данных
Система типов данных YDB и PostgreSQL похожи, но при этом не совпадают.
Использование данных таблиц, созданных в YQL синтаксисе, в синтаксисе PostgreSQL
Типы данных из YDB автоматически преобразовываются в соответствующие им типы PostgreSQL. Преобразование выполняется неявно с помощью команды ToPg.
Пример:
- 
Создадим таблицу YDB с помощью YQL-синтаксиса CREATE TABLE `test_table`(col INT, PRIMARY KEY(col));
- 
Добавим туда тестовые данные INSERT INTO test_table(col) VALUES(1)
- 
Прочитаем эти данные с помощью PostgreSQL-синтаксиса. YQL-тип данных INTбыл автоматически переведен в PostgreSQL-типint4, над которым была выполнена операция инкремента.psql -c "SELECT col+1 AS col FROM test_table" col --- 2 (1 row)
Так как все вычисления выполняются внутри YDB, то для для каждого PostgreSQL типа создан "зеркальный тип" в YDB. Например, тип text из PostgreSQL при обработке внутри YDB будет иметь тип pgtext. Это сделано, чтобы обеспечить точную семантику работы типов PostgreSQL внутри YDB. При преобразовании типа из PostgreSQL в YDB применяется правило, что для каждого такого типа добавляется префикс pg, после чего используется оригинальное имя типа из PostgreSQL.
Таблица соответствия типов данных YQL, при их использовании в PostgreSQL запросах:
| YQL | PostgreSQL | Название PostgreSQL-типа в YDB | 
|---|---|---|
| Bool | bool | pgbool | 
| Int8 | int2 | pgint2 | 
| Uint8 | int2 | pgint2 | 
| Int16 | int2 | pgint2 | 
| Uint16 | int4 | pgint4 | 
| Int32 | int4 | pgint4 | 
| Uint32 | int8 | pgint8 | 
| Int64 | int8 | pgint8 | 
| Uint64 | numeric | pgnumeric | 
| Float | float4 | pgfloat4 | 
| Double | float8 | pgfloat8 | 
| String | bytea | pgbytea | 
| Utf8 | text | pgtext | 
| Yson | bytea | pgbytea | 
| Json | json | pgjson | 
| Uuid | uuid | pguuid | 
| JsonDocument | jsonb | pgjsonb | 
| Date | date | pgdate | 
| Datetime | timestamp | pgtimestamp | 
| Timestamp | timestamp | pgtimestamp | 
| Interval | interval | pginterval | 
| TzDate | text | pgtext | 
| TzDatetime | text | pgtext | 
| TzTimestamp | text | pgtext | 
| Date32 | date | pgdate | 
| Datetime64 | timestamp | pgtimestamp | 
| Timestamp64 | timestamp | pgtimestamp | 
| Interval64 | interval | pginterval | 
| TzDate32 | text | |
| TzDatetime64 | text | |
| TzTimestamp64 | text | |
| Decimal | numeric | pgnumeric | 
| DyNumber | numeric | pgnumeric | 
Использование данных таблиц, созданных в PostgreSQL синтаксисе, в синтаксисе YQL
При использовании данных из таблиц, созданных в PostgreSQL синтаксисе, YQL интерпретирует данные в этих колонках, как специальные типы из семейства pg*.
Пример:
- 
Создадим таблицу YDB с помощью PostgreSQL-синтаксиса CREATE TABLE test_table_pg(numeric INT, PRIMARY KEY(col));
- 
Добавим туда тестовые данные INSERT INTO test_table_pg(col) VALUES(10)
- 
Прочитаем эти данные с помощью YQL-синтаксиса ydb sql -s "SELECT col+1 AS col FROM test_table_pg" col --- "11" -- pgnumeric (1 row)
Правила преобразования типов PostgreSQL в типы YQL приведены в таблице:
| PostgreSQL | YQL | 
|---|---|
| bool | pgbool | 
| int2 | pgint2 | 
| int4 | pgint4 | 
| int8 | pgint8 | 
| numeric | pgnumeric | 
| float4 | pgfloat4 | 
| float8 | pgfloat8 | 
| bytea | pgbytea | 
| text | pgtext | 
| bytea | pgbytea | 
| json | pgjson | 
| uuid | pguuid | 
| jsonb | pgjsonb | 
| date | pgdate | 
| timestamp | pgtimestamp | 
| interval | pginterval | 
| text | pgtext | 
| date | pgdate | 
| timestamp | pgtimestamp | 
| interval | pginterval | 
| numeric | pgnumeric | 
Встроенные функции YQL ориентированы на работу с собственными типами данных, например, Ip::FromString получает на вход типы данных Utf8 или String. Поэтому встроенные функции YQL не могут работать с типами данных PostgreSQL. Для решения задачи конвертации типов существует функция FromPg, выполняющая преобразование данных из типов PostgreSQL в типы YQL.
Пример:
- 
Создадим таблицу YDB с помощью PostgreSQL-синтаксиса CREATE TABLE test_table_pg_ip(col text, PRIMARY KEY(col));
- 
Добавим туда тестовые данные INSERT INTO test_table_pg_ip(col) VALUES('::ffff:77.75.155.3')
- 
Прочитаем эти данные с помощью YQL-синтаксиса: ydb sql -s "SELECT Ip::ToString(Ip::GetSubnet(Ip::FromString(col))) AS subnet FROM test_table_pg_ip" Status: GENERIC_ERROR Issues: <main>: Error: Type annotation, code: 1030 <main>:1:1: Error: At function: RemovePrefixMembers, At function: PersistableRepr, At function: SqlProject, At function: SqlProjectItem <main>:1:12: Error: At function: Apply, Callable is produced by Udf: Ip.FromString <main>:1:23: Error: Mismatch type argument #1, type diff: String!=pgtext
- 
Для работы функции Ip::FromStringнеобходимо предварительно выполнить преобразование типов данных с помощью функцииPgFrom:ydb sql -s "SELECT Ip::ToString(Ip::GetSubnet(Ip::FromString(FromPg(col))) AS subnet FROM test_table_pg_ip" ┌────────┐ │ subnet │ ├────────┤ │ "::" │ └────────┘
Кроме этого, при работе с PostgreSQL типами данных можно использовать функции самого PostgreSQL непосредственно из YQL-синтаксиса:
- 
Создадим таблицу YDB с помощью PostgreSQL-синтаксиса CREATE TABLE test_table_array(col INT, col2 _INT, PRIMARY KEY(col));
- 
Добавим туда тестовые данные INSERT INTO test_table_array(col, col2) VALUES(1, '{1,2,3}')
- 
Вызовем встроенную функцию PostgreSQL array_length:ydb sql -s "select Pg::array_length(col2, 1) FROM test_table_array" col --- "3" -- число элементов в массиве (1 row)