Перейти к основному содержимому
Перейти к основному содержимому

Справочная документация по pg_clickhouse

Описание

pg_clickhouse — это расширение PostgreSQL, позволяющее удалённо выполнять запросы к базам данных ClickHouse, включая реализацию [обёртки внешних данных (foreign data wrapper)]. Оно поддерживает PostgreSQL 13 и новее и ClickHouse 23 и новее.

Начало работы

Самый простой способ попробовать pg_clickhouse — использовать [образ Docker], который содержит стандартный образ PostgreSQL с расширением pg_clickhouse:

docker run --name pg_clickhouse -e POSTGRES_PASSWORD=my_pass \
       -d ghcr.io/clickhouse/pg_clickhouse:18
docker exec -it pg_clickhouse psql -U postgres

См. руководство, чтобы начать импортировать таблицы ClickHouse и пробрасывать запросы.

Использование

CREATE EXTENSION pg_clickhouse;
CREATE SERVER taxi_srv FOREIGN DATA WRAPPER clickhouse_fdw
       OPTIONS(driver 'binary', host 'localhost', dbname 'taxi');
CREATE USER MAPPING FOR CURRENT_USER SERVER taxi_srv
       OPTIONS (user 'default');
CREATE SCHEMA taxi;
IMPORT FOREIGN SCHEMA taxi FROM SERVER taxi_srv INTO taxi;

Политика версионирования

pg_clickhouse следует [Семантическому версионированию] для своих публичных релизов.

  • Старшая версия увеличивается при изменениях API
  • Младшая версия увеличивается при обратно совместимых изменениях SQL
  • Патч-версия увеличивается при изменениях только на уровне бинарных файлов

После установки PostgreSQL отслеживает два варианта номера версии:

  • Версия библиотеки (определяется PG_MODULE_MAGIC в PostgreSQL 18 и выше) включает полную семантическую версию, видимую в выводе функции pg_get_loaded_modules().
  • Версия расширения (определяется в control-файле) включает только старшую и младшую версии, видимую в таблице pg_catalog.pg_extension, в выводе функции pg_available_extension_versions() и в \dx pg_clickhouse.

На практике это означает, что релиз, который увеличивает патч-версию, например с v0.1.0 до v0.1.1, применяется ко всем базам данных, которые загрузили v0.1, и им не нужно выполнять ALTER EXTENSION, чтобы получить преимущества обновления.

Релиз, который увеличивает младшую или старшую версии, напротив, будет сопровождаться SQL-скриптами обновления, и все существующие базы данных, в которых установлено это расширение, должны выполнить ALTER EXTENSION pg_clickhouse UPDATE, чтобы получить преимущества обновления.

Справочник по SQL DDL

В следующих SQL-выражениях DDL используется pg_clickhouse.

CREATE EXTENSION

Используйте CREATE EXTENSION, чтобы добавить pg_clickhouse в базу данных:

CREATE EXTENSION pg_clickhouse;

Используйте WITH SCHEMA, чтобы установить его в конкретную схему (рекомендуется):

CREATE SCHEMA ch;
CREATE EXTENSION pg_clickhouse WITH SCHEMA ch;

ALTER EXTENSION

Используйте ALTER EXTENSION, чтобы изменить расширение pg_clickhouse. Примеры:

  • После установки новой версии pg_clickhouse используйте оператор UPDATE:

    ALTER EXTENSION pg_clickhouse UPDATE;
    
  • Используйте SET SCHEMA, чтобы перенести расширение в другую схему:

    CREATE SCHEMA ch;
    ALTER EXTENSION pg_clickhouse SET SCHEMA ch;
    

DROP EXTENSION

Используйте DROP EXTENSION, чтобы удалить расширение pg_clickhouse из базы данных:

DROP EXTENSION pg_clickhouse;

Эта команда завершится с ошибкой, если существуют какие-либо объекты, зависящие от pg_clickhouse. Используйте предложение CASCADE, чтобы удалить и их:

DROP EXTENSION pg_clickhouse CASCADE;

CREATE SERVER

Используйте CREATE SERVER, чтобы создать внешний сервер для подключения к серверу ClickHouse. Пример:

CREATE SERVER taxi_srv FOREIGN DATA WRAPPER clickhouse_fdw
       OPTIONS(driver 'binary', host 'localhost', dbname 'taxi');

Поддерживаемые параметры:

  • driver: драйвер подключения к ClickHouse, который следует использовать — либо "binary", либо "http". Обязательный.
  • dbname: база данных ClickHouse, которая будет использоваться при подключении. По умолчанию "default".
  • host: имя хоста сервера ClickHouse. По умолчанию "localhost".
  • port: порт для подключения к серверу ClickHouse. Значения по умолчанию:
    • 9440, если driver — "binary" и host является хостом ClickHouse Cloud
    • 9004, если driver — "binary" и host не является хостом ClickHouse Cloud
    • 8443, если driver — "http" и host является хостом ClickHouse Cloud
    • 8123, если driver — "http" и host не является хостом ClickHouse Cloud

ALTER SERVER

Используйте оператор ALTER SERVER, чтобы изменить внешний сервер. Пример:

ALTER SERVER taxi_srv OPTIONS (SET driver 'http');

Параметры те же, что и для CREATE SERVER.

DROP SERVER

Используйте DROP SERVER для удаления внешнего сервера:

DROP SERVER taxi_srv;

Эта команда приведёт к ошибке, если от сервера зависят какие-либо другие объекты. Используйте CASCADE, чтобы также удалить эти зависимости:

DROP SERVER taxi_srv CASCADE;

CREATE USER MAPPING

Используйте CREATE USER MAPPING, чтобы сопоставить пользователя PostgreSQL с пользователем ClickHouse. Например, чтобы сопоставить текущего пользователя PostgreSQL с удалённым пользователем ClickHouse при подключении к внешнему серверу taxi_srv:

CREATE USER MAPPING FOR CURRENT_USER SERVER taxi_srv
       OPTIONS (user 'demo');

Поддерживаемые параметры:

  • user: Имя пользователя ClickHouse. По умолчанию — "default".
  • password: Пароль пользователя ClickHouse.

ALTER USER MAPPING

Используйте ALTER USER MAPPING, чтобы изменить определение сопоставления пользователя:

ALTER USER MAPPING FOR CURRENT_USER SERVER taxi_srv
       OPTIONS (SET user 'default');

Параметры совпадают с параметрами для CREATE USER MAPPING.

DROP USER MAPPING

Используйте DROP USER MAPPING для удаления сопоставления пользователя:

DROP USER MAPPING FOR CURRENT_USER SERVER taxi_srv;

IMPORT FOREIGN SCHEMA

Используйте IMPORT FOREIGN SCHEMA, чтобы импортировать все таблицы, определённые в базе данных ClickHouse, в качестве внешних таблиц в схему PostgreSQL:

CREATE SCHEMA taxi;
IMPORT FOREIGN SCHEMA demo FROM SERVER taxi_srv INTO taxi;

Используйте LIMIT TO, чтобы импортировать только определённые таблицы:

IMPORT FOREIGN SCHEMA demo LIMIT TO (trips) FROM SERVER taxi_srv INTO taxi;

Используйте EXCEPT для исключения таблиц:

IMPORT FOREIGN SCHEMA demo EXCEPT (users) FROM SERVER taxi_srv INTO taxi;

pg_clickhouse получит список всех таблиц в указанной базе данных ClickHouse («demo» в приведённых выше примерах), получит определения столбцов для каждой из них и выполнит команды CREATE FOREIGN TABLE для создания внешних таблиц. Столбцы будут определены с использованием поддерживаемых типов данных и, где это можно определить, опций, поддерживаемых CREATE FOREIGN TABLE.

Imported Identifier Case Preservation

IMPORT FOREIGN SCHEMA выполняет quote_identifier() для импортируемых имён таблиц и столбцов, что приводит к заключению в двойные кавычки идентификаторов с прописными буквами или пробелами. Такие имена таблиц и столбцов, соответственно, должны указываться в двойных кавычках в запросах PostgreSQL. Имена, состоящие только из строчных букв и не содержащие пробелов, не нужно заключать в кавычки.

Например, для следующей таблицы ClickHouse:

 CREATE OR REPLACE TABLE test
 (
     id UInt64,
     Name TEXT,
     updatedAt DateTime DEFAULT now()
 )
 ENGINE = MergeTree
 ORDER BY id;

IMPORT FOREIGN SCHEMA создаёт следующую внешнюю таблицу:`

 CREATE TABLE test
 (
     id          BIGINT      NOT NULL,
     "Name"      TEXT        NOT NULL,
     "updatedAt" TIMESTAMPTZ NOT NULL
 );

Поэтому в запросах необходимо корректно использовать кавычки, например:

 SELECT id, "Name", "updatedAt" FROM test;

Чтобы создать объекты с другими именами или именами целиком в нижнем регистре (а значит, нечувствительными к регистру), используйте CREATE FOREIGN TABLE.

CREATE FOREIGN TABLE

Используйте CREATE FOREIGN TABLE, чтобы создать внешнюю таблицу, которая может выполнять запросы к данным в базе данных ClickHouse:

CREATE FOREIGN TABLE uact (
    user_id    bigint NOT NULL,
    page_views int,
    duration   smallint,
    sign       smallint
) SERVER taxi_srv OPTIONS(
    table_name 'uact'
    engine 'CollapsingMergeTree'
);

Поддерживаемые параметры таблицы:

  • database: Имя удалённой базы данных. По умолчанию используется база данных, определённая для внешнего сервера.
  • table_name: Имя удалённой таблицы. По умолчанию используется имя, указанное для внешней таблицы.
  • engine: [Движок таблицы], используемый таблицей ClickHouse. Для CollapsingMergeTree() и AggregatingMergeTree() pg_clickhouse автоматически применяет параметры к функциональным выражениям, выполняемым над таблицей.

Используйте тип данных, соответствующий удалённому типу данных ClickHouse для каждого столбца. Для столбцов типа AggregateFunction Type и SimpleAggregateFunction Type сопоставьте тип данных с типом ClickHouse, передаваемым в функцию, и укажите имя агрегатной функции через соответствующий параметр столбца:

  • AggregateFunction: Имя агрегатной функции, применённой к столбцу типа AggregateFunction Type
  • SimpleAggregateFunction: Имя агрегатной функции, применённой к столбцу типа SimpleAggregateFunction Type

Пример:

(aggregatefunction 'sum')

CREATE FOREIGN TABLE test (
    column1 bigint  OPTIONS(AggregateFunction 'uniq'),
    column2 integer OPTIONS(AggregateFunction 'anyIf'),
    column3 bigint  OPTIONS(AggregateFunction 'quantiles(0.5, 0.9)')
) SERVER clickhouse_srv;

Для столбцов с типом AggregateFunction pg_clickhouse автоматически добавит Merge к агрегатной функции, применяемой к этому столбцу.

ALTER FOREIGN TABLE

Используйте команду ALTER FOREIGN TABLE, чтобы изменить определение внешней таблицы:

ALTER TABLE table ALTER COLUMN b OPTIONS (SET AggregateFunction 'count');

Поддерживаемые параметры таблиц и столбцов совпадают с параметрами для CREATE FOREIGN TABLE.

DROP FOREIGN TABLE

Используйте оператор DROP FOREIGN TABLE для удаления внешней таблицы:

DROP FOREIGN TABLE uact;

Эта команда завершится с ошибкой, если существуют какие-либо объекты, зависящие от внешней таблицы. Используйте ключевое слово CASCADE, чтобы удалить и их:

DROP FOREIGN TABLE uact CASCADE;

Справочник по SQL DML

SQL-выражения DML, приведённые ниже, могут использовать pg_clickhouse. Примеры зависят от следующих таблиц ClickHouse, созданных скриптом make-logs.sql:

CREATE TABLE logs (
    req_id    Int64 NOT NULL,
    start_at   DateTime64(6, 'UTC') NOT NULL,
    duration  Int32 NOT NULL,
    resource  Text  NOT NULL,
    method    Enum8('GET' = 1, 'HEAD', 'POST', 'PUT', 'DELETE', 'CONNECT', 'OPTIONS', 'TRACE', 'PATCH', 'QUERY') NOT NULL,
    node_id   Int64 NOT NULL,
    response  Int32 NOT NULL
) ENGINE = MergeTree
  ORDER BY start_at;

CREATE TABLE nodes (
    node_id Int64 NOT NULL,
    name    Text  NOT NULL,
    region  Text  NOT NULL,
    arch    Text  NOT NULL,
    os      Text  NOT NULL
) ENGINE = MergeTree
  PRIMARY KEY node_id;

EXPLAIN

Команда EXPLAIN работает как и ожидается, но опция VERBOSE приводит к тому, что выполняется запрос ClickHouse "Remote SQL":

try=# EXPLAIN (VERBOSE)
       SELECT resource, avg(duration) AS average_duration
         FROM logs
        GROUP BY resource;
                                     QUERY PLAN
------------------------------------------------------------------------------------
 Foreign Scan  (cost=1.00..5.10 rows=1000 width=64)
   Output: resource, (avg(duration))
   Relations: Aggregate on (logs)
   Remote SQL: SELECT resource, avg(duration) FROM "default".logs GROUP BY resource
(4 rows)

Этот запрос пробрасывается в ClickHouse в виде удалённого SQL через плановый узел "Foreign Scan".

SELECT

Используйте оператор SELECT для выполнения запросов к таблицам pg_clickhouse аналогично любым другим таблицам:

try=# SELECT start_at, duration, resource FROM logs WHERE req_id = 4117909262;
          start_at          | duration |    resource
----------------------------+----------+----------------
 2025-12-05 15:07:32.944188 |      175 | /widgets/totam
(1 row)

pg_clickhouse работает таким образом, чтобы по возможности передавать выполнение запроса в ClickHouse, включая агрегатные функции. Используйте EXPLAIN, чтобы определить степень такого делегирования. Для приведённого выше запроса, например, всё выполнение полностью передаётся в ClickHouse.

try=# EXPLAIN (VERBOSE, COSTS OFF)
       SELECT start_at, duration, resource FROM logs WHERE req_id = 4117909262;
                                             QUERY PLAN
-----------------------------------------------------------------------------------------------------
 Foreign Scan on public.logs
   Output: start_at, duration, resource
   Remote SQL: SELECT start_at, duration, resource FROM "default".logs WHERE ((req_id = 4117909262))
(3 rows)

pg_clickhouse также проталкивает выполнение операций JOIN к таблицам, расположенным на том же удалённом сервере:

try=# EXPLAIN (ANALYZE, VERBOSE)
       SELECT name, count(*), round(avg(duration))
         FROM logs
         LEFT JOIN nodes on logs.node_id = nodes.node_id
        GROUP BY name;
                                                                                  QUERY PLAN
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 Foreign Scan  (cost=1.00..5.10 rows=1000 width=72) (actual time=3.201..3.221 rows=8.00 loops=1)
   Output: nodes.name, (count(*)), (round(avg(logs.duration), 0))
   Relations: Aggregate on ((logs) LEFT JOIN (nodes))
   Remote SQL: SELECT r2.name, count(*), round(avg(r1.duration), 0) FROM  "default".logs r1 ALL LEFT JOIN "default".nodes r2 ON (((r1.node_id = r2.node_id))) GROUP BY r2.name
   FDW Time: 0.086 ms
 Planning Time: 0.335 ms
 Execution Time: 3.261 ms
(7 rows)

Выполнение JOIN с локальной таблицей приводит к менее эффективным запросам без тщательной настройки. В этом примере мы создаём локальную копию таблицы nodes и выполняем соединение с ней вместо удалённой таблицы:

try=# CREATE TABLE local_nodes AS SELECT * FROM nodes;
SELECT 8

try=# EXPLAIN (ANALYZE, VERBOSE)
       SELECT name, count(*), round(avg(duration))
         FROM logs
         LEFT JOIN local_nodes on logs.node_id = local_nodes.node_id
        GROUP BY name;
                                                             QUERY PLAN
-------------------------------------------------------------------------------------------------------------------------------------
 HashAggregate  (cost=147.65..150.65 rows=200 width=72) (actual time=6.215..6.235 rows=8.00 loops=1)
   Output: local_nodes.name, count(*), round(avg(logs.duration), 0)
   Group Key: local_nodes.name
   Batches: 1  Memory Usage: 32kB
   Buffers: shared hit=1
   ->  Hash Left Join  (cost=31.02..129.28 rows=2450 width=36) (actual time=2.202..5.125 rows=1000.00 loops=1)
         Output: local_nodes.name, logs.duration
         Hash Cond: (logs.node_id = local_nodes.node_id)
         Buffers: shared hit=1
         ->  Foreign Scan on public.logs  (cost=10.00..20.00 rows=1000 width=12) (actual time=2.089..3.779 rows=1000.00 loops=1)
               Output: logs.req_id, logs.start_at, logs.duration, logs.resource, logs.method, logs.node_id, logs.response
               Remote SQL: SELECT duration, node_id FROM "default".logs
               FDW Time: 1.447 ms
         ->  Hash  (cost=14.90..14.90 rows=490 width=40) (actual time=0.090..0.091 rows=8.00 loops=1)
               Output: local_nodes.name, local_nodes.node_id
               Buckets: 1024  Batches: 1  Memory Usage: 9kB
               Buffers: shared hit=1
               ->  Seq Scan on public.local_nodes  (cost=0.00..14.90 rows=490 width=40) (actual time=0.069..0.073 rows=8.00 loops=1)
                     Output: local_nodes.name, local_nodes.node_id
                     Buffers: shared hit=1
 Planning:
   Buffers: shared hit=14
 Planning Time: 0.551 ms
 Execution Time: 6.589 ms

В этом случае мы можем переложить больше работы по агрегации на ClickHouse, выполняя группировку по node_id вместо локального столбца, а затем выполнить JOIN с таблицей соответствия:

try=# EXPLAIN (ANALYZE, VERBOSE)
       WITH remote AS (
           SELECT node_id, count(*), round(avg(duration))
             FROM logs
            GROUP BY node_id
       )
       SELECT name, remote.count, remote.round
         FROM remote
         JOIN local_nodes
           ON remote.node_id = local_nodes.node_id
        ORDER BY name;
                                                          QUERY PLAN
-------------------------------------------------------------------------------------------------------------------------------
 Sort  (cost=65.68..66.91 rows=490 width=72) (actual time=4.480..4.484 rows=8.00 loops=1)
   Output: local_nodes.name, remote.count, remote.round
   Sort Key: local_nodes.name
   Sort Method: quicksort  Memory: 25kB
   Buffers: shared hit=4
   ->  Hash Join  (cost=27.60..43.79 rows=490 width=72) (actual time=4.406..4.422 rows=8.00 loops=1)
         Output: local_nodes.name, remote.count, remote.round
         Inner Unique: true
         Hash Cond: (local_nodes.node_id = remote.node_id)
         Buffers: shared hit=1
         ->  Seq Scan on public.local_nodes  (cost=0.00..14.90 rows=490 width=40) (actual time=0.010..0.016 rows=8.00 loops=1)
               Output: local_nodes.node_id, local_nodes.name, local_nodes.region, local_nodes.arch, local_nodes.os
               Buffers: shared hit=1
         ->  Hash  (cost=15.10..15.10 rows=1000 width=48) (actual time=4.379..4.381 rows=8.00 loops=1)
               Output: remote.count, remote.round, remote.node_id
               Buckets: 1024  Batches: 1  Memory Usage: 9kB
               ->  Subquery Scan on remote  (cost=1.00..15.10 rows=1000 width=48) (actual time=4.337..4.360 rows=8.00 loops=1)
                     Output: remote.count, remote.round, remote.node_id
                     ->  Foreign Scan  (cost=1.00..5.10 rows=1000 width=48) (actual time=4.330..4.349 rows=8.00 loops=1)
                           Output: logs.node_id, (count(*)), (round(avg(logs.duration), 0))
                           Relations: Aggregate on (logs)
                           Remote SQL: SELECT node_id, count(*), round(avg(duration), 0) FROM "default".logs GROUP BY node_id
                           FDW Time: 0.055 ms
 Planning:
   Buffers: shared hit=5
 Planning Time: 0.319 ms
 Execution Time: 4.562 ms

Узел "Foreign Scan" теперь выполняет агрегацию по node_id на удалённой стороне, уменьшая количество строк, которые нужно вернуть в Postgres, с 1000 (всех) до всего лишь 8, по одной на каждый узел.

PREPARE, EXECUTE, DEALLOCATE

Начиная с версии v0.1.2, pg_clickhouse поддерживает параметризованные запросы, как правило создаваемые командой PREPARE:

try=# PREPARE avg_durations_between_dates(date, date) AS
       SELECT date(start_at), round(avg(duration)) AS average_duration
         FROM logs
        WHERE date(start_at) BETWEEN $1 AND $2
        GROUP BY date(start_at)
        ORDER BY date(start_at);
PREPARE

Используйте EXECUTE как обычно, чтобы выполнить подготовленный запрос:

try=# EXECUTE avg_durations_between_dates('2025-12-09', '2025-12-13');
    date    | average_duration
------------+------------------
 2025-12-09 |              190
 2025-12-10 |              194
 2025-12-11 |              197
 2025-12-12 |              190
 2025-12-13 |              195
(5 rows)

pg_clickhouse, как и обычно, проталкивает агрегации на нижележащий уровень, что видно из подробного вывода EXPLAIN:

try=# EXPLAIN (VERBOSE) EXECUTE avg_durations_between_dates('2025-12-09', '2025-12-13');
                                                                                                            QUERY PLAN
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 Foreign Scan  (cost=1.00..5.10 rows=1000 width=36)
   Output: (date(start_at)), (round(avg(duration), 0))
   Relations: Aggregate on (logs)
   Remote SQL: SELECT date(start_at), round(avg(duration), 0) FROM "default".logs WHERE ((date(start_at) >= '2025-12-09')) AND ((date(start_at) <= '2025-12-13')) GROUP BY (date(start_at)) ORDER BY date(start_at) ASC NULLS LAST
(4 rows)

Обратите внимание, что отправлены полные значения дат, а не шаблоны параметров. Это справедливо для первых пяти запросов, как описано в PostgreSQL [PREPARE notes]. При шестом выполнении он отправляет в ClickHouse параметры запроса в формате {param:type}: параметры:

                                                                                                         QUERY PLAN
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 Foreign Scan  (cost=1.00..5.10 rows=1000 width=36)
   Output: (date(start_at)), (round(avg(duration), 0))
   Relations: Aggregate on (logs)
   Remote SQL: SELECT date(start_at), round(avg(duration), 0) FROM "default".logs WHERE ((date(start_at) >= {p1:Date})) AND ((date(start_at) <= {p2:Date})) GROUP BY (date(start_at)) ORDER BY date(start_at) ASC NULLS LAST
(4 rows)

Используйте DEALLOCATE, чтобы освободить подготовленный запрос:

try=# DEALLOCATE avg_durations_between_dates;
DEALLOCATE

INSERT

Используйте команду INSERT, чтобы вставлять значения в удалённую таблицу ClickHouse:

try=# INSERT INTO nodes(node_id, name, region, arch, os)
VALUES (9,  'Augustin Gamarra', 'us-west-2', 'amd64', 'Linux')
     , (10, 'Cerisier', 'us-east-2', 'amd64', 'Linux')
     , (11, 'Dewalt', 'use-central-1', 'arm64', 'macOS')
;
INSERT 0 3

COPY

Используйте команду COPY, чтобы вставить пакет строк в удалённую таблицу ClickHouse:

try=# COPY logs FROM stdin CSV;
4285871863,2025-12-05 11:13:58.360760,206,/widgets,POST,8,401
4020882978,2025-12-05 11:33:48.248450,199,/users/1321945,HEAD,3,200
3231273177,2025-12-05 12:20:42.158575,220,/search,GET,2,201
\.
>> COPY 3

⚠️ Ограничения Batch API

В pg_clickhouse ещё не реализована поддержка PostgreSQL FDW Batch Insert API. Поэтому COPY в настоящее время использует команды INSERT для вставки записей. Это будет улучшено в одном из следующих релизов.

LOAD

Используйте LOAD, чтобы загрузить общую библиотеку pg_clickhouse:

try=# LOAD 'pg_clickhouse';
LOAD

Обычно нет необходимости использовать LOAD, так как Postgres автоматически загружает pg_clickhouse при первом использовании любой из его возможностей (функции, внешние таблицы и т. д.).

Единственный случай, когда может быть полезно выполнить LOAD для pg_clickhouse, — это задать с помощью SET параметры pg_clickhouse перед выполнением зависящих от них запросов.

SET

Используйте SET, чтобы задать параметр времени выполнения pg_clickhouse.session_settings. Этот параметр настраивает [параметры ClickHouse], которые будут применены к последующим запросам. Пример:

SET pg_clickhouse.session_settings = 'join_use_nulls 1, final 1';

По умолчанию — join_use_nulls 1. Установите пустую строку, чтобы перейти к использованию настроек сервера ClickHouse.

SET pg_clickhouse.session_settings = '';

Синтаксис: список пар ключ/значение, разделённых запятыми; ключ и значение в паре разделяются одним или несколькими пробелами. Ключи должны соответствовать [настройкам ClickHouse]. В значениях экранируйте пробелы, запятые и обратные косые черты с помощью обратной косой черты:

SET pg_clickhouse.session_settings = 'join_algorithm grace_hash\,hash';

Или используйте значения в одинарных кавычках, чтобы избежать экранирования пробелов и запятых; рассмотрите возможность использования dollar quoting, чтобы избежать необходимости двойного заключения в кавычки:

SET pg_clickhouse.session_settings = $$join_algorithm 'grace_hash,hash'$$;

Если для вас важна читаемость и нужно задать много параметров, используйте несколько строк, например:

SET pg_clickhouse.session_settings TO $$
    connect_timeout 2,
    count_distinct_implementation uniq,
    final 1,
    group_by_use_nulls 1,
    join_algorithm 'prefer_partial_merge',
    join_use_nulls 1,
    log_queries_min_type QUERY_FINISH,
    max_block_size 32768,
    max_execution_time 45,
    max_result_rows 1024,
    metrics_perf_events_list 'this,that',
    network_compression_method ZSTD,
    poll_interval 5,
    totals_mode after_having_auto
$$;

pg_clickhouse не проверяет настройки, а передаёт их в ClickHouse для каждого запроса. Тем самым он поддерживает все настройки для каждой версии ClickHouse.

Обратите внимание, что pg_clickhouse должен быть загружен до задания pg_clickhouse.session_settings; либо используйте [предзагрузку общей библиотеки], либо просто используйте один из объектов расширения, чтобы гарантировать его загрузку.

ALTER ROLE

Используйте команду SET оператора ALTER ROLE для предварительной загрузки pg_clickhouse и/или настройки его параметров для определённых ролей:

try=# ALTER ROLE CURRENT_USER SET session_preload_libraries = pg_clickhouse;
ALTER ROLE

try=# ALTER ROLE CURRENT_USER SET pg_clickhouse.session_settings = 'final 1';
ALTER ROLE

Используйте команду RESET оператора ALTER ROLE, чтобы сбросить предзагрузку pg_clickhouse и/или его параметры:

try=# ALTER ROLE CURRENT_USER RESET session_preload_libraries;
ALTER ROLE

try=# ALTER ROLE CURRENT_USER RESET pg_clickhouse.session_settings;
ALTER ROLE

Предварительная загрузка

Если каждому или почти каждому подключению к Postgres нужно использовать pg_clickhouse, рассмотрите возможность использования [предварительной загрузки общих библиотек], чтобы он загружался автоматически:

session_preload_libraries

Загружает разделяемую библиотеку для каждого нового соединения с PostgreSQL:

session_preload_libraries = pg_clickhouse

Полезно, чтобы применять обновления без перезапуска сервера: достаточно просто переподключиться. Этот параметр также можно задать для отдельных пользователей или ролей с помощью ALTER ROLE.

shared_preload_libraries

Загружает общую библиотеку в родительский процесс PostgreSQL при запуске:

shared_preload_libraries = pg_clickhouse

Полезно для экономии памяти и снижения накладных расходов на загрузку в каждом сеансе, но при обновлении библиотеки требуется перезапуск кластера.

Справочник функций и операторов

Типы данных

pg_clickhouse сопоставляет следующие типы данных ClickHouse с типами данных PostgreSQL:

ClickHousePostgreSQLПримечания
Boolboolean
Datedate
Date32date
DateTimetimestamp
Decimalnumeric
Float32real
Float64double precision
IPv4inet
IPv6inet
Int16smallint
Int32integer
Int64bigint
Int8smallint
JSONjsonbтолько для HTTP-движка
Stringtext
UInt16integer
UInt32bigint
UInt64bigintОшибка для значений > максимального значения BIGINT
UInt8smallint
UUIDuuid

Функции

Эти функции предоставляют интерфейс для выполнения запросов к базе данных ClickHouse.

clickhouse_raw_query

SELECT clickhouse_raw_query(
    'CREATE TABLE t1 (x String) ENGINE = Memory',
    'host=localhost port=8123'
);

Подключается к серверу ClickHouse через его HTTP‑интерфейс, выполняет один запрос и отключается. Необязательный второй аргумент задаёт строку подключения, по умолчанию host=localhost port=8123. Поддерживаемые параметры подключения:

  • host: Хост, к которому выполняется подключение; обязательный параметр.
  • port: HTTP‑порт для подключения; по умолчанию 8123, если только host не является хостом ClickHouse Cloud, — в этом случае по умолчанию используется 8443
  • dbname: Имя базы данных, к которой выполняется подключение.
  • username: Имя пользователя, под которым выполняется подключение; по умолчанию default
  • password: Пароль, используемый для аутентификации; по умолчанию пароль не используется

Полезно для запросов, которые не возвращают записей; результаты запросов, которые возвращают значения, возвращаются в виде одного текстового значения:

SELECT clickhouse_raw_query(
    'SELECT schema_name, schema_owner from information_schema.schemata',
    'host=localhost port=8123'
);
      clickhouse_raw_query
---------------------------------
 INFORMATION_SCHEMA      default+
 default default                +
 git     default                +
 information_schema      default+
 system  default                +

(1 row)

Функции pushdown

Все встроенные функции PostgreSQL, используемые в условных выражениях (предложения HAVING и WHERE) для выполнения запросов к внешним таблицам ClickHouse, автоматически передаются на выполнение в ClickHouse с теми же именами и сигнатурами. Однако у некоторых функций другие имена или сигнатуры, и их необходимо сопоставить с их эквивалентами в ClickHouse. pg_clickhouse сопоставляет следующие функции:

Пользовательские функции

Эти пользовательские функции, созданные pg_clickhouse, обеспечивают проталкивание (pushdown) удалённых запросов для отдельных функций ClickHouse, не имеющих эквивалентов в PostgreSQL. Если какую-либо из этих функций нельзя протолкнуть, будет возбуждено исключение.

Pushdown-приведения типов

pg_clickhouse проталкивает приведения типов, такие как CAST(x AS bigint), для совместимых типов данных. Для несовместимых типов операция pushdown завершится ошибкой; если x в этом примере — ClickHouse UInt64, ClickHouse откажется выполнять такое приведение.

Для того чтобы выполнять pushdown-приведения к несовместимым типам данных, pg_clickhouse предоставляет следующие функции. Они вызывают исключение в PostgreSQL, если приведение не было протолкнуто в ClickHouse.

Pushdown-агрегаты

Эти агрегатные функции PostgreSQL выполняются в ClickHouse посредством pushdown.

Пользовательские агрегаты

Эти пользовательские агрегатные функции, созданные pg_clickhouse, обеспечивают проталкивание удалённых запросов (foreign query pushdown) для отдельных агрегатных функций ClickHouse, не имеющих эквивалентов в PostgreSQL. Если какую-либо из этих функций невозможно протолкнуть, будет сгенерировано исключение.

Pushdown Ordered Set Aggregates

Эти [ordered-set aggregate functions] сопоставляются с [Parametric aggregate functions] в ClickHouse: их прямой аргумент передается как параметр, а выражения ORDER BY — как аргументы. Например, этот запрос PostgreSQL:

SELECT percentile_cont(0.25) WITHIN GROUP (ORDER BY a) FROM t1;

Соответствует следующему запросу ClickHouse:

SELECT quantile(0.25)(a) FROM t1;

Учтите, что явные суффиксы ORDER BY DESC и NULLS FIRST не поддерживаются и приведут к ошибке.

Автор

David E. Wheeler

Copyright (c) 2025-2026, ClickHouse

"Документация PostgreSQL: предварительная загрузка разделяемых библиотек [PREPARE notes]: https://www.postgresql.org/docs/current/sql-prepare.html#SQL-PREPARE-NOTES "Документация PostgreSQL: примечания к PREPARE" [query parameters]: https://clickhouse.com/docs/guides/developer/stored-procedures-and-prepared-statements#alternatives-to-prepared-statements-in-clickhouse "Документация ClickHouse: альтернативы подготовленным запросам в ClickHouse"