Skip to content
ClickHouse Docs
ClickHouse DocsClickHouse Docs

Продвинутые запросы

QueryContexts

ClickHouse Connect выполняет стандартные запросы в контексте QueryContext. QueryContext содержит ключевые структуры, используемые для построения запросов к базе данных ClickHouse, а также конфигурацию, которая используется для преобразования результата в QueryResult или другую структуру данных ответа. Сюда входят сам запрос, параметры, настройки, форматы чтения и другие свойства.

QueryContext можно получить с помощью клиентского метода create_query_context. Этот метод принимает те же параметры, что и основной метод запроса. Затем этот контекст можно передать в методы query, query_df или query_np как именованный аргумент context вместо части или всех остальных аргументов этих методов. Обратите внимание, что дополнительные аргументы, указанные при вызове метода, переопределяют любые свойства QueryContext.

Наиболее понятный сценарий использования QueryContext — отправка одного и того же запроса с разными значениями параметров привязки. Все значения параметров можно обновить, вызвав метод QueryContext.set_parameters и передав ему словарь, а любое отдельное значение — вызвав QueryContext.set_parameter с нужной парой key, value.

qc = client.create_query_context(
    query="SELECT {k:Int32}",
    parameters={"k": 13},
)
result = client.query(context=qc)
assert result.first_row == (13,)

qc.set_parameter("k", 79)
result = client.query(context=qc)
assert result.first_row == (79,)

Обратите внимание, что объекты QueryContext не являются потокобезопасными, однако в многопоточной среде можно получить их копию, вызвав метод QueryContext.updated_copy.

Стриминг запросов

Клиент ClickHouse Connect предоставляет несколько методов для получения данных в виде потока (реализованного как генератор Python):

  • query_column_block_stream – Возвращает данные запроса блоками как последовательность столбцов с использованием собственных объектов Python
  • query_row_block_stream – Возвращает данные запроса как блок строк с использованием собственных объектов Python
  • query_rows_stream – Возвращает данные запроса как последовательность строк с использованием собственных объектов Python
  • query_np_stream – Возвращает каждый блок данных запроса ClickHouse как массив NumPy
  • query_df_stream – Возвращает каждый блок данных запроса ClickHouse как DataFrame Pandas
  • query_arrow_stream – Возвращает данные запроса как объекты PyArrow RecordBatch
  • query_df_arrow_stream – Возвращает каждый батч Arrow как DataFrame Pandas или Polars, выбранный с помощью dataframe_library

Каждый метод возвращает StreamContext, который необходимо открыть с помощью оператора with. Методы стриминга async client ожидаются через await и открываются с помощью async with.

Блоки данных

ClickHouse Connect обрабатывает все данные из основного метода query как поток блоков, получаемых от сервер ClickHouse. Эти блоки передаются в собственном формате "Native" в ClickHouse и из ClickHouse. «Блок» — это просто последовательность столбцов бинарных данных, где каждый столбец содержит одинаковое количество значений указанного типа данных. (Поскольку ClickHouse — колоночная база данных, он хранит эти данные в похожем виде.) Размер блока, возвращаемого запросом, определяется двумя пользовательскими настройками, которые можно задавать на нескольких уровнях (профиль пользователя, пользователь, сеанс или запрос). Вот они:

Независимо от preferred_block_size_bytes, блок не будет превышать max_block_size строк. Фактический размер может быть меньше и не должен считаться стабильным.

При использовании одного из методов клиента query_*_stream результаты возвращаются по блокам. ClickHouse Connect загружает только один блок за раз. Это позволяет обрабатывать большие объёмы данных без необходимости загружать в память весь большой результирующий набор. Обратите внимание: приложение должно быть готово обработать любое количество блоков, а точный размер каждого блока нельзя контролировать.

HTTP-буфер данных для медленной обработки

Если приложение получает блоки значительно медленнее, чем сервер их отправляет, HTTP-соединение может закрыться до завершения обработки. Увеличьте значение общей настройки http_buffer_size, если у приложения достаточно памяти для буферизации большего объёма данных ответа. По умолчанию это значение равно 10 MiB. Данные ответа, сжатые с помощью lz4 и zstd, остаются в этом буфере в сжатом виде, что увеличивает его фактическую ёмкость.

StreamContexts

Каждый из методов query_*_stream (например, query_row_block_stream) возвращает объект ClickHouse StreamContext, который сочетает в себе Python-контекст и генератор. Вот базовое использование:

with client.query_row_block_stream(
    "SELECT pickup, dropoff, pickup_longitude, pickup_latitude FROM taxi_trips"
) as stream:
    for block in stream:
        for row in block:
            process_trip(row)

Обратите внимание: попытка использовать StreamContext без оператора with вызовет ошибку. Использование контекста Python гарантирует, что поток (в данном случае — потоковый HTTP-ответ) будет корректно закрыт, даже если будут прочитаны не все данные и/или в ходе обработки возникнет исключение. Кроме того, StreamContext можно использовать для чтения потока только один раз. Попытка использовать StreamContext после выхода из него приведёт к ошибке StreamClosedError.

Если соединение прерывается во время чтения результата, вместо молчаливого возврата усечённого результата возникает StreamFailureError. Его сообщение соответствует настройке клиента show_clickhouse_errors.

Вы можете использовать свойство source объекта StreamContext, чтобы получить доступ к родительскому объекту результата, который содержит имена столбцов и типы. Для большинства потоков это QueryResult; методы query_np_stream и query_df_stream вместо этого возвращают NumpyResult.

Типы потоков

Метод query_column_block_stream возвращает блок как последовательность данных столбцов в нативных типах данных Python. Если использовать приведённые выше запросы taxi_trips, возвращённые данные будут представлять собой список, где каждый элемент — это ещё один список (или кортеж), содержащий все данные соответствующего столбца. То есть block[0] будет кортежем, содержащим только строковые значения. Форматы с ориентацией по столбцам чаще всего используются для выполнения агрегатных операций над всеми значениями в столбце, например для подсчёта общей стоимости поездок.

Метод query_row_block_stream возвращает блок как последовательность строк, как в традиционной реляционной базе данных. Для поездок на такси возвращённые данные будут представлять собой список, где каждый элемент — это ещё один список, представляющий строку данных. То есть block[0] будет содержать все поля по порядку для первой поездки на такси, block[1] — строку со всеми полями второй поездки на такси, и так далее. Результаты с ориентацией по строкам обычно используются для отображения или преобразования данных.

Метод query_rows_stream автоматически переходит к следующему блоку и выдаёт по одной строке за раз. Это построчный аналог query_row_block_stream.

Метод query_np_stream возвращает каждый блок как массив NumPy. Когда все столбцы результата имеют общий NumPy dtype, массив является двумерным и имеет форму (строки, столбцы). Смешанные результаты возвращаются как одномерный структурированный массив или используют dtype object.

Метод query_df_stream возвращает каждый блок ClickHouse как двумерный Pandas DataFrame. Ниже приведён пример, показывающий, что объект StreamContext можно использовать как контекстный менеджер в отложенном режиме (но только один раз).

df_stream = client.query_df_stream("SELECT * FROM hits")
column_names = df_stream.source.column_names
with df_stream:
    for df in df_stream:
        process_dataframe(df)

Метод query_df_arrow_stream преобразует батчи Arrow в Pandas или Polars DataFrame. Выберите библиотеку с помощью dataframe_library (по умолчанию — "pandas").

Наконец, метод query_arrow_stream оборачивает ответ ClickHouse ArrowStream в StreamContext. На каждой итерации возвращается PyArrow RecordBatch.

Примеры стриминга

Поток строк

import clickhouse_connect

client = clickhouse_connect.get_client()

# Stream large result sets row by row
with client.query_rows_stream("SELECT number, number * 2 as doubled FROM system.numbers LIMIT 100000") as stream:
    for row in stream:
        print(row)  # Process each row
        # Output:
        # (0, 0)
        # (1, 2)
        # (2, 4)
        # Additional rows follow

Потоковая передача блоков со строками

import clickhouse_connect

client = clickhouse_connect.get_client()

# Stream in blocks of rows (more efficient than row-by-row)
with client.query_row_block_stream("SELECT number, number * 2 FROM system.numbers LIMIT 100000") as stream:
    for block in stream:
        print(f"Received block with {len(block)} rows")

Потоковая передача Pandas DataFrame

import clickhouse_connect

client = clickhouse_connect.get_client()

# Stream query results as Pandas DataFrames
with client.query_df_stream("SELECT number, toString(number) AS str FROM system.numbers LIMIT 100000") as stream:
    for df in stream:
        # Process each DataFrame block
        print(f"Received DataFrame with {len(df)} rows")
        print(df.head(3))

Потоковая передача батчей Arrow

import clickhouse_connect

client = clickhouse_connect.get_client()

# Stream query results as Arrow record batches
with client.query_arrow_stream("SELECT * FROM large_table") as stream:
    for arrow_batch in stream:
        # Process each Arrow batch
        print(f"Received Arrow batch with {arrow_batch.num_rows} rows")

Асинхронный стриминг строк

import asyncio

import clickhouse_connect


async def main():
    async_client = await clickhouse_connect.get_async_client()
    async with await async_client.query_rows_stream(
        "SELECT number FROM numbers(100000)"
    ) as stream:
        async for row in stream:
            print(row)


asyncio.run(main())

Запросы NumPy, Pandas и Arrow

ClickHouse Connect предоставляет специализированные методы для работы со структурами данных NumPy, Pandas и Arrow. Эти методы позволяют получать результаты запроса напрямую в этих популярных форматах данных без ручного преобразования.

Запросы NumPy

Метод query_np возвращает результаты запроса в виде массива NumPy, а не объекта ClickHouse Connect QueryResult.

import clickhouse_connect

client = clickhouse_connect.get_client()

# Query returns a NumPy array
np_array = client.query_np("SELECT number, number * 2 AS doubled FROM system.numbers LIMIT 5")

print(type(np_array))
# Output:
# <class 'numpy.ndarray'>

print(np_array)
# Output:
# [[0 0]
#  [1 2]
#  [2 4]
#  [3 6]
#  [4 8]]

Запросы Pandas

Метод query_df возвращает результаты запроса в виде объекта Pandas DataFrame, а не ClickHouse Connect QueryResult.

import clickhouse_connect

client = clickhouse_connect.get_client()

# Query returns a Pandas DataFrame
df = client.query_df("SELECT number, number * 2 AS doubled FROM system.numbers LIMIT 5")

print(type(df))
# Output: <class 'pandas.core.frame.DataFrame'>
print(df)
# Output:
#    number  doubled
# 0       0        0
# 1       1        2
# 2       2        4
# 3       3        6
# 4       4        8

Запросы PyArrow

Метод query_arrow возвращает таблицу PyArrow, напрямую используя формат вывода ClickHouse Arrow. Он принимает query, parameters, settings, external_data и transport_settings. Параметр use_strings определяет, будут ли столбцы ClickHouse String выводиться как строки Arrow или как двоичные значения.

import clickhouse_connect

client = clickhouse_connect.get_client()

# Query returns a PyArrow Table
arrow_table = client.query_arrow("SELECT number, toString(number) AS str FROM system.numbers LIMIT 3")

print(type(arrow_table))
# Output:
# <class 'pyarrow.lib.Table'>

print(arrow_table)
# Output:
# pyarrow.Table
# number: uint64 not null
# str: string not null
# ----
# number: [[0,1,2]]
# str: [["0","1","2"]]

DataFrames на базе Arrow

ClickHouse Connect поддерживает эффективное создание DataFrame из результатов в формате Arrow с помощью query_df_arrow и query_df_arrow_stream. Эти методы позволяют избежать преобразования через объекты строк в Python и повторно использовать буферы Arrow там, где это поддерживается целевой библиотекой:

  • query_df_arrow: Выполняет запрос, используя выходной формат ClickHouse Arrow, и возвращает DataFrame.
    • dataframe_library="pandas" возвращает DataFrame Pandas 2.0 или более поздней версии с использованием pd.ArrowDtype.
    • dataframe_library="polars" возвращает DataFrame Polars, созданный с помощью pl.from_arrow.
  • query_df_arrow_stream: Передаёт батчи Arrow в виде DataFrame Pandas или Polars.

Запрос к DataFrame на базе Arrow

import clickhouse_connect

client = clickhouse_connect.get_client()

# Query returns a Pandas DataFrame with Arrow dtypes (requires pandas 2.x)
df = client.query_df_arrow(
    "SELECT number, toString(number) AS str FROM system.numbers LIMIT 3",
    dataframe_library="pandas"
)

print(df.dtypes)
# Output:
# number    uint64[pyarrow]
# str       string[pyarrow]
# dtype: object

# Or use Polars
polars_df = client.query_df_arrow(
    "SELECT number, toString(number) AS str FROM system.numbers LIMIT 3",
    dataframe_library="polars"
)
print(polars_df.dtypes)
# Output:
# [UInt64, String]

# Streaming into batches of DataFrames (polars shown)
with client.query_df_arrow_stream(
    "SELECT number, toString(number) AS str FROM system.numbers LIMIT 100000", dataframe_library="polars"
) as stream:
    for df_batch in stream:
        print(f"Received {type(df_batch)} batch with {len(df_batch)} rows and dtypes: {df_batch.dtypes}")

Примечания и ограничения

  • ClickHouse определяет схему Arrow. Типы, для которых в Arrow нет прямого представления, могут возвращаться в совместимом физическом типе, включая двоичные поля. Проверяйте table.schema или dtypes DataFrame, прежде чем применять специфичные для приложения преобразования.
  • Результаты Pandas на базе Arrow требуют Pandas 2.0 или более поздней версии.
  • use_strings определяет, будут ли столбцы ClickHouse String использовать строковые или двоичные поля Arrow, если сервер поддерживает output_format_arrow_string_as_string.
  • tz_mode="schema" пока не поддерживается методами запросов на базе Arrow. Они выдают предупреждение и сохраняют метаданные часового пояса, переданные в ответе Arrow.

Форматы чтения

Форматы чтения определяют значения, возвращаемые query, query_np и query_df. Они не применяются к методам raw или Arrow, поскольку эти методы напрямую используют формат вывода сервера. Например, если задать для UUID формат чтения "string", будут возвращаться строки UUID, а не объекты uuid.UUID.

Аргумент "тип данных" для любой функции форматирования может включать подстановочные шаблоны. Формат задается одной строкой в нижнем регистре. Обертки-контейнеры, такие как Array, Nullable и LowCardinality, сохраняют выбранный формат для своего типа элементов.

Форматы чтения можно задавать на нескольких уровнях:

  • Глобально — с помощью методов, определенных в пакете clickhouse_connect.datatypes.format. Это задает формат для настроенного типа данных во всех запросах.
from clickhouse_connect.datatypes.format import set_read_format

# Return both IPv6 and IPv4 values as strings
set_read_format("IPv*", "string")

# Return all Date types as the underlying epoch second or epoch day
set_read_format("Date*", "int")
  • Для всего запроса — с использованием необязательного аргумента словаря query_formats. В этом случае любой столбец (или подстолбец) указанных типов данных будет использовать настроенный формат.
# Return any UUID column as a string
client.query(
    "SELECT user_id, user_uuid, device_uuid FROM users",
    query_formats={"UUID": "string"},
)
  • Для отдельного столбца результата используйте необязательный словарь column_formats. Каждый ключ — это имя возвращаемого столбца. Его значение — строка формата или вложенное сопоставление имён типов ClickHouse с форматами, что полезно для Tuple, Map и других контейнерных типов.
# Return IPv6 values in the `dev_address` column as strings
client.query(
    "SELECT device_id, dev_address, gw_address FROM devices",
    column_formats={"dev_address": "string"},
)

Параметры форматов чтения (типы Python)

Тип ClickHouse Нативный тип Python Форматы чтения Комментарии
Int[8-64], UInt[8-32] int string
UInt64 int signed Superset пока не поддерживает большие беззнаковые значения UInt64
[U]Int[128,256] int string Значения int в Pandas и NumPy ограничены 64 битами, поэтому они могут возвращаться как строки
BFloat16 float - Все значения float в Python внутри представлены 64 битами
Float32 float string Все значения float в Python внутри представлены 64 битами
Float64 float string
Decimal decimal.Decimal -
String str bytes Столбцы String в ClickHouse не имеют встроенного кодирования, поэтому также используются для бинарных данных переменной длины
FixedString bytes string FixedString — это байтовые массивы фиксированного размера, но иногда они интерпретируются как строки Python
Enum[8,16] str int Нативный формат возвращает метки; int возвращает базовое целочисленное значение.
Date datetime.date int Целочисленный формат возвращает количество дней с 1970-01-01.
Date32 datetime.date int Целочисленный формат возвращает расширенное знаковое смещение в днях.
DateTime datetime.datetime int Целочисленный формат возвращает секунды epoch.
DateTime64 datetime.datetime int Целочисленный формат возвращает ticks с точностью столбца. Python datetime ограничен микросекундами.
Time datetime.timedelta int, string, time Целочисленный формат возвращает секунды. Формат time ограничен значениями, которые помещаются в datetime.time.
Time64 datetime.timedelta int, string, time Целочисленный формат возвращает ticks с точностью столбца. Python timedelta ограничен микросекундами.
IPv4 ipaddress.IPv4Address string, int IP-адреса можно читать как строки или целые числа.
IPv6 ipaddress.IPv6Address string IP-адреса можно читать как строки; при правильном форматировании их можно вставлять как IP-адреса
Tuple dict or tuple tuple, dict, json Именованные Tuple по умолчанию возвращают словари; неименованные Tuple возвращают кортежи.
Map dict -
Nested Sequence[dict] -
UUID uuid.UUID string UUID можно читать как строки, отформатированные в соответствии с RFC 4122
JSON dict string По умолчанию возвращается словарь Python. Формат string возвращает JSON-строку
Variant object typed typed возвращает TypedVariant(value, type_name), чтобы сохранить исходный тип элемента.
Dynamic object - Возвращает соответствующий тип Python для типа данных ClickHouse, хранящегося в значении
QBit list[float] - Если установлен NumPy, он автоматически используется для более быстрого транспонирования битов.

Внешние данные

Запросы ClickHouse могут принимать внешние данные в любом поддерживаемом формате ввода. Клиент отправляет данные как часть запроса, а запрос может ссылаться на них как на временную внешнюю таблицу. См. документацию ClickHouse по внешним данным. Методы клиентских запросов принимают объект clickhouse_connect.driver.external.ExternalData через параметр external_data.

Name Type Description
file_path str Путь к файлу в локальной файловой системе, из которого считываются внешние данные. Необходимо указать либо file_path, либо data
file_name str Имя внешнего "файла" данных. Если не указано, берётся из имени файла в file_path. Имя внешней таблицы — имя файла без расширения
data bytes Внешние данные в бинарном виде (вместо чтения из файла). Необходимо указать либо data, либо file_path
fmt str ClickHouse формат ввода данных. По умолчанию используется TSV
types str or seq of str Список типов данных столбцов во внешних данных. Если указана строка, типы должны быть разделены запятыми. Необходимо указать либо types, либо structure
structure str or seq of str Список пар «имя столбца + тип данных» в данных (см. примеры). Необходимо указать либо structure, либо types
mime_type str Необязательный MIME-тип данных файла. В настоящее время ClickHouse игнорирует этот HTTP-подзаголовок

В этом примере внешний CSV-файл объединяется через JOIN с таблицей directors, хранящейся на сервере:

import clickhouse_connect

from clickhouse_connect.driver.external import ExternalData

client = clickhouse_connect.get_client()
ext_data = ExternalData(
    file_path="/data/movies.csv",
    fmt="CSV",
    structure=[
        "movie String",
        "year UInt16",
        "rating Decimal32(3)",
        "director String",
    ],
)
result = client.query(
    "SELECT name, avg(rating) "
    "FROM directors INNER JOIN movies ON directors.name = movies.director "
    "GROUP BY directors.name",
    external_data=ext_data,
).result_rows

Дополнительные внешние файлы данных можно добавить в исходный объект ExternalData с помощью метода add_file, который принимает те же параметры, что и конструктор. При использовании HTTP все внешние данные передаются как часть загрузки файла multi-part/form-data.

backend chDB не поддерживает внешние данные.

Часовые пояса

Значения ClickHouse DateTime и DateTime64 передаются как числовые значения на основе epoch. ClickHouse Connect преобразует их в объекты Python datetime, используя метаданные столбцов, переопределения запроса и политику часовых поясов клиента.

У клиента есть два независимых параметра часового пояса:

  • tz_source задаёт резервный часовой пояс для столбцов без явных метаданных часового пояса:
    • "auto" используется по умолчанию. В этом режиме используется часовой пояс сервера, если клиент может надёжно определить его с учётом переходов на летнее время; в противном случае используется локальный часовой пояс.
    • "server" всегда использует часовой пояс сервера.
    • "local" всегда использует локальный часовой пояс процесса.
  • tz_mode управляет учётом часового пояса:
    • "naive_utc" используется по умолчанию. Результаты в UTC и эквивалентных UTC часовых поясах возвращаются как naive-объекты datetime для обратной совместимости.
    • "aware" сохраняет tzinfo UTC и возвращает UTC-значения с информацией о часовом поясе.
    • "schema" возвращает значения с информацией о часовом поясе только в том случае, если тип столбца объявляет часовой пояс, и naive-значения для обычных столбцов DateTime/DateTime64.

Для обычных запросов с "naive_utc" и "aware" активный часовой пояс выбирается в следующем порядке:

  1. Переопределение column_tzs для отдельного столбца.
  2. Метаданные часового пояса в типе столбца ClickHouse.
  3. Переопределение query_tz для всего запроса.
  4. Информация о часовом поясе, возвращённая в HTTP-ответе.
  5. Резервный часовой пояс, выбранный через tz_source.

tz_mode="schema" игнорирует часовые пояса запроса и резервные часовые пояса, но явное переопределение column_tzs по-прежнему имеет приоритет.

result = client.query(
    "SELECT "
    "toDateTime('2026-01-15 12:00:00', 'UTC') AS utc_time, "
    "toDateTime('2026-01-15 12:00:00', 'America/Denver') AS denver_time",
    tz_mode="aware",
)

assert result.first_row[0].tzinfo is not None
assert result.first_row[1].tzinfo is not None

Названия часовых поясов обрабатываются стандартным модулем библиотеки zoneinfo. В Windows tzdata устанавливается автоматически. В минимальных Linux-образах без базы часовых поясов IANA установите clickhouse-connect[tzdata].

Результаты Pandas сохраняют естественную точность каждого типа ClickHouse, например datetime64[s] для DateTime и datetime64[ms] для DateTime64(3). Методы DataFrame на базе Arrow query_df_arrow и query_df_arrow_stream пока не поддерживают tz_mode="schema" и выдают предупреждение, если запрошен этот режим. query_arrow и query_arrow_stream возвращают метаданные часового пояса из ответа Arrow без изменений.

Navigation