Saltar al contenido principal

QueryContexts

ClickHouse Connect ejecuta consultas estándar dentro de un QueryContext. El QueryContext contiene las estructuras clave que se utilizan para crear consultas en la base de datos ClickHouse, así como la configuración usada para procesar el resultado en un QueryResult u otra estructura de datos de respuesta. Esto incluye la propia consulta, parámetros, ajustes, formatos de lectura y otras propiedades. Se puede obtener un QueryContext mediante el método create_query_context del cliente. Este método acepta los mismos parámetros que el método principal de consulta. Después, este contexto de consulta puede pasarse a los métodos query, query_df o query_np como argumento con nombre context, en lugar de cualquiera o de todos los demás argumentos de esos métodos. Tenga en cuenta que los argumentos adicionales especificados en la llamada al método sobrescribirán cualquier propiedad de QueryContext. El caso de uso más claro de un QueryContext es enviar la misma consulta con distintos valores de parámetros enlazados. Todos los valores de los parámetros pueden actualizarse llamando al método QueryContext.set_parameters con un diccionario, o bien se puede actualizar un valor individual llamando a QueryContext.set_parameter con el par key, value deseado.
client.create_query_context(query='SELECT value1, value2 FROM data_table WHERE key = {k:Int32}',
                            parameters={'k': 2},
                            column_oriented=True)
result = client.query(context=qc)
assert result.result_set[1][0] == 'second_value2'
qc.set_parameter('k', 1)
result = test_client.query(context=qc)
assert result.result_set[1][0] == 'first_value2'
Ten en cuenta que los QueryContexts no son seguros para su uso en varios hilos, pero se puede obtener una copia en un entorno multihilo llamando al método QueryContext.updated_copy.

Consultas en streaming

El cliente ClickHouse Connect proporciona varios métodos para recuperar datos como un stream (implementado como un generador de Python):
  • query_column_block_stream — Devuelve los datos de la consulta en bloques, como una secuencia de columnas, utilizando objetos nativos de Python
  • query_row_block_stream — Devuelve los datos de la consulta como un bloque de filas utilizando objetos nativos de Python
  • query_rows_stream — Devuelve los datos de la consulta como una secuencia de filas utilizando objetos nativos de Python
  • query_np_stream — Devuelve cada bloque de datos de la consulta de ClickHouse como un array de NumPy
  • query_df_stream — Devuelve cada bloque de datos de la consulta de ClickHouse como un DataFrame de Pandas
  • query_arrow_stream — Devuelve los datos de la consulta en bloques de registros de PyArrow
  • query_df_arrow_stream — Devuelve cada bloque de datos de la consulta de ClickHouse como un DataFrame de Pandas basado en Arrow o un DataFrame de Polars, según el argumento con nombre dataframe_library (el valor predeterminado es “pandas”).
Cada uno de estos métodos devuelve un objeto ContextStream que debe abrirse mediante una sentencia with para empezar a consumir el stream.

Bloques de datos

ClickHouse Connect procesa todos los datos del método query principal como un flujo de bloques recibidos del servidor ClickHouse. Estos bloques se transmiten hacia y desde ClickHouse en el formato personalizado “Native”. Un “bloque” es simplemente una secuencia de columnas de datos binarios, en la que cada columna contiene la misma cantidad de valores de datos del tipo de dato especificado. (Como base de datos columnar, ClickHouse almacena estos datos de forma similar). El tamaño de un bloque devuelto por una consulta depende de dos configuraciones de usuario que pueden establecerse en varios niveles (perfil de usuario, usuario, sesión o consulta). Son:
  • max_block_size — Límite del tamaño del bloque en filas. Valor predeterminado: 65536.
  • preferred_block_size_bytes — Límite flexible del tamaño del bloque en bytes. Valor predeterminado: 1,000,0000.
Independientemente de preferred_block_size_setting, ningún bloque tendrá nunca más de max_block_size filas. Según el tipo de consulta, los bloques devueltos reales pueden ser de cualquier tamaño. Por ejemplo, las consultas a una tabla distribuida que abarca muchos segmentos pueden contener bloques más pequeños recuperados directamente de cada segmento. Al usar uno de los métodos query_*_stream del cliente, los resultados se devuelven bloque por bloque. ClickHouse Connect solo carga un bloque a la vez. Esto permite procesar grandes cantidades de datos sin necesidad de cargar en memoria todo un conjunto de resultados grande. Ten en cuenta que la aplicación debe estar preparada para procesar cualquier cantidad de bloques y que el tamaño exacto de cada bloque no puede controlarse.

Búfer de datos HTTP para procesamiento lento

Debido a las limitaciones del protocolo HTTP, si los bloques se procesan a una velocidad significativamente menor que aquella a la que el servidor ClickHouse transmite los datos, el servidor ClickHouse cerrará la conexión, lo que hará que se lance una excepción en el hilo de procesamiento. Esto puede mitigarse en parte aumentando el tamaño del búfer de streaming HTTP (cuyo valor predeterminado es de 10 megabytes) mediante la configuración común http_buffer_size. Los valores altos de http_buffer_size suelen ser adecuados en esta situación si la aplicación dispone de suficiente memoria. Los datos del búfer se almacenan comprimidos si se usa compresión lz4 o zstd, por lo que usar estos tipos de compresión aumentará el tamaño total del búfer disponible.

StreamContexts

Cada uno de los métodos query_*_stream (como query_row_block_stream) devuelve un objeto StreamContext de ClickHouse, que combina un contexto y un generador de Python. Este es el uso básico:
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:
            <hacer algo con cada fila de datos de viaje de Python>
Ten en cuenta que intentar usar un StreamContext sin una instrucción with generará un error. El uso de un contexto de Python garantiza que el stream (en este caso, una respuesta HTTP en streaming) se cierre correctamente aunque no se consuman todos los datos y/o se produzca una excepción durante el procesamiento. Además, los StreamContext solo pueden usarse una vez para consumir el stream. Intentar usar un StreamContext después de haber salido de él producirá un StreamClosedError. Puedes usar la propiedad source del StreamContext para acceder al objeto QueryResult padre, que incluye los nombres de las columnas y los tipos.

Tipos de flujo

El método query_column_block_stream devuelve el bloque como una secuencia de datos de columna almacenados como tipos de datos nativos de Python. Si usamos las consultas taxi_trips anteriores, los datos devueltos serán una lista en la que cada elemento es otra lista (o tupla) que contiene todos los datos de la columna correspondiente. Así, block[0] sería una tupla que solo contendría cadenas. Los formatos orientados a columnas se usan sobre todo para realizar operaciones de agregación sobre todos los valores de una columna, como sumar las tarifas totales. El método query_row_block_stream devuelve el bloque como una secuencia de filas, como en una base de datos relacional tradicional. Para los trayectos de taxi, los datos devueltos serán una lista en la que cada elemento es otra lista que representa una fila de datos. Así, block[0] contendría todos los campos (en orden) del primer trayecto de taxi, block[1] contendría una fila con todos los campos del segundo trayecto de taxi, y así sucesivamente. Los resultados orientados a filas normalmente se usan en procesos de visualización o transformación. query_row_stream es un método auxiliar que pasa automáticamente al siguiente bloque al iterar por el flujo. Por lo demás, es idéntico a query_row_block_stream. El método query_np_stream devuelve cada bloque como un array de NumPy bidimensional. Internamente, los arrays de NumPy se almacenan (normalmente) como columnas, por lo que no se necesitan métodos distintos para filas o columnas. La “forma” del array de NumPy se expresará como (columnas, filas). La biblioteca NumPy proporciona muchos métodos para manipular arrays de NumPy. Ten en cuenta que, si todas las columnas de la consulta comparten el mismo dtype de NumPy, el array de NumPy devuelto también tendrá un único dtype y podrá reformarse o rotarse sin cambiar realmente su estructura interna. El método query_df_stream devuelve cada bloque de ClickHouse como un DataFrame de Pandas bidimensional. Aquí tienes un ejemplo que muestra que el objeto StreamContext puede usarse como contexto de forma diferida (pero solo una vez).
df_stream = client.query_df_stream('SELECT * FROM hits')
column_names = df_stream.source.column_names
with df_stream:
    for df in df_stream:
        <do something with the pandas DataFrame>
El método query_df_arrow_stream devuelve cada bloque de ClickHouse como un DataFrame con el backend de dtype de PyArrow. Este método admite DataFrames de Pandas (2.x o posterior) y de Polars mediante el parámetro dataframe_library (cuyo valor predeterminado es "pandas"). Cada iteración genera un DataFrame convertido a partir de record batches de PyArrow, lo que ofrece mejor rendimiento y mayor eficiencia de memoria para ciertos tipos de datos. Por último, el método query_arrow_stream devuelve un resultado de ClickHouse en formato ArrowStream como un pyarrow.ipc.RecordBatchStreamReader encapsulado en StreamContext. Cada iteración del stream devuelve un RecordBlock de PyArrow.

Ejemplos de streaming

Transmitir filas en streaming

import clickhouse_connect

client = clickhouse_connect.get_client()

# Transmitir grandes conjuntos de resultados fila por fila
with client.query_rows_stream("SELECT number, number * 2 as doubled FROM system.numbers LIMIT 100000") as stream:
    for row in stream:
        print(row)  # Procesar cada fila
        # Salida:
        # (0, 0)
        # (1, 2)
        # (2, 4)
        # ....

Transmitir bloques de filas

import clickhouse_connect

client = clickhouse_connect.get_client()

# Transmitir en bloques de filas (más eficiente que fila por fila)
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")
        # Salida:
        # Bloque recibido con 65409 filas
        # Bloque recibido con 34591 filas

Transmitir DataFrames de Pandas

import clickhouse_connect

client = clickhouse_connect.get_client()

# Transmitir resultados de consulta como Pandas DataFrames
with client.query_df_stream("SELECT number, toString(number) AS str FROM system.numbers LIMIT 100000") as stream:
    for df in stream:
        # Procesar cada bloque de DataFrame
        print(f"Received DataFrame with {len(df)} rows")
        print(df.head(3))
        # Salida:
        # DataFrame recibido con 65409 filas
        #    number str
        # 0       0   0
        # 1       1   1
        # 2       2   2
        # DataFrame recibido con 34591 filas
        #    number    str
        # 0   65409  65409
        # 1   65410  65410
        # 2   65411  65411

Transmitir lotes de Arrow

import clickhouse_connect

client = clickhouse_connect.get_client()

# Transmitir resultados de consulta como lotes de registros Arrow
with client.query_arrow_stream("SELECT * FROM large_table") as stream:
    for arrow_batch in stream:
        # Procesar cada lote Arrow
        print(f"Received Arrow batch with {arrow_batch.num_rows} rows")
        # Salida:
        # Lote Arrow recibido con 65409 filas
        # Lote Arrow recibido con 34591 filas

Consultas con NumPy, Pandas y Arrow

ClickHouse Connect proporciona métodos de consulta especializados para trabajar con estructuras de datos de NumPy, Pandas y Arrow. Estos métodos le permiten obtener los resultados de las consultas directamente en estos formatos de datos populares, sin necesidad de conversión manual.

Consultas con NumPy

El método query_np devuelve los resultados de la consulta como un array de NumPy en lugar de un QueryResult de ClickHouse Connect.
import clickhouse_connect

client = clickhouse_connect.get_client()

# La consulta devuelve un array de NumPy
np_array = client.query_np("SELECT number, number * 2 AS doubled FROM system.numbers LIMIT 5")

print(type(np_array))
# Salida:
# <class "numpy.ndarray">

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

Consultas con Pandas

El método query_df devuelve los resultados de la consulta como un DataFrame de Pandas en lugar de un QueryResult de ClickHouse Connect.
import clickhouse_connect

client = clickhouse_connect.get_client()

# La consulta devuelve un DataFrame de Pandas
df = client.query_df("SELECT number, number * 2 AS doubled FROM system.numbers LIMIT 5")

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

Consultas con PyArrow

El método query_arrow devuelve los resultados de la consulta como una tabla de PyArrow. Utiliza directamente el formato Arrow de ClickHouse, por lo que solo comparte tres argumentos con el método principal query: query, parameters y settings. Además, hay un argumento adicional, use_strings, que determina si la tabla Arrow mostrará los tipos String de ClickHouse como cadenas (si es True) o como bytes (si es False).
import clickhouse_connect

client = clickhouse_connect.get_client()

# La consulta devuelve una tabla PyArrow
arrow_table = client.query_arrow("SELECT number, toString(number) AS str FROM system.numbers LIMIT 3")

print(type(arrow_table))
# Salida:
# <class "pyarrow.lib.Table">

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

DataFrames basados en Arrow

ClickHouse Connect admite la creación rápida y eficiente en memoria de DataFrames a partir de resultados de Arrow mediante los métodos query_df_arrow y query_df_arrow_stream. Son envoltorios ligeros de los métodos de consulta de Arrow y realizan conversiones sin copia a DataFrames cuando es posible:
  • query_df_arrow: Ejecuta la consulta con el formato de salida Arrow de ClickHouse y devuelve un DataFrame.
    • Para dataframe_library='pandas', devuelve un DataFrame de pandas 2.x que usa tipos de datos basados en Arrow (pd.ArrowDtype). Esto requiere pandas 2.x y aprovecha búferes sin copia siempre que sea posible para ofrecer un rendimiento excelente y una baja sobrecarga de memoria.
    • Para dataframe_library='polars', devuelve un DataFrame de Polars creado a partir de la tabla Arrow (pl.from_arrow), que es igual de eficiente y puede no requerir copia, según los datos.
  • query_df_arrow_stream: Transmite los resultados como una secuencia de DataFrames (pandas 2.x o Polars) convertidos a partir de lotes del flujo Arrow.

Consulta a un DataFrame basado en Arrow

import clickhouse_connect

client = clickhouse_connect.get_client()

# La consulta devuelve un DataFrame de Pandas con tipos Arrow (requiere 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)
# Salida:
# number    uint64[pyarrow]
# str       string[pyarrow]
# dtype: object

# O bien, usar Polars
polars_df = client.query_df_arrow(
    "SELECT number, toString(number) AS str FROM system.numbers LIMIT 3",
    dataframe_library="polars"
)
print(df.dtypes)
# Salida:
# [UInt64, String]

# Streaming en lotes de DataFrames (ejemplo con polars)
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}")
        # Salida:
        # Received <class 'polars.dataframe.frame.DataFrame'> batch with 65409 rows and dtypes: [UInt64, String]
        # Received <class 'polars.dataframe.frame.DataFrame'> batch with 34591 rows and dtypes: [UInt64, String]

Notas y advertencias

  • Correspondencia de tipos de Arrow: Al devolver datos en formato Arrow, ClickHouse asigna los tipos a los tipos de Arrow compatibles más cercanos. Algunos tipos de ClickHouse no tienen un equivalente nativo en Arrow y se devuelven como bytes sin procesar en campos de Arrow (normalmente BINARY o FIXED_SIZE_BINARY).
    • Ejemplos: IPv4 se representa como Arrow UINT32; IPv6 y los enteros grandes (Int128/UInt128/Int256/UInt256) suelen representarse como FIXED_SIZE_BINARY/BINARY con bytes sin procesar.
    • En estos casos, la columna del DataFrame contendrá valores de bytes respaldados por el campo de Arrow; corresponde al código cliente interpretar o convertir esos bytes según la semántica de ClickHouse.
  • Los tipos de datos de Arrow no compatibles (p. ej., UUID/ENUM como verdaderos tipos de Arrow) no se emiten; los valores se representan usando el tipo de Arrow compatible más cercano (a menudo, como bytes binarios) para la salida.
  • Requisito de pandas: Los dtypes basados en Arrow requieren pandas 2.x. Para versiones anteriores de pandas, use query_df (sin Arrow) en su lugar.
  • Strings frente a binario: La opción use_strings (cuando es compatible con la configuración del servidor output_format_arrow_string_as_string) controla si las columnas String de ClickHouse se devuelven como cadenas de Arrow o como binario.

Ejemplos de conversión entre tipos incompatibles de ClickHouse/Arrow

Cuando ClickHouse devuelve columnas como datos binarios sin procesar (p. ej., FIXED_SIZE_BINARY o BINARY), corresponde al código de la aplicación convertir esos bytes en los tipos de Python adecuados. Los ejemplos siguientes muestran que algunas conversiones pueden realizarse con las API de bibliotecas de DataFrame, mientras que otras pueden requerir enfoques de Python puro, como struct.unpack (que sacrifican rendimiento, pero mantienen la flexibilidad). Las columnas Date pueden llegar como UINT16 (días desde la época Unix, 1970‑01‑01). Convertirlas dentro del DataFrame es eficiente y sencillo:
# Polars
df = df.with_columns(pl.col("event_date").cast(pl.Date))

# Pandas
df["event_date"] = pd.to_datetime(df["event_date"], unit="D")
Las columnas como Int128 pueden llegar como FIXED_SIZE_BINARY con bytes sin procesar. Polars ofrece soporte nativo para enteros de 128 bits:
# Polars - soporte nativo
df = df.with_columns(pl.col("data").bin.reinterpret(dtype=pl.Int128, endianness="little"))
A partir de NumPy 2.3 no hay ningún dtype público para enteros de 128 bits, así que debemos recurrir a Python puro y podemos hacer algo como esto:
# Suponiendo que tenemos un dataframe de pandas con una columna Int128 de dtype fixed_size_binary[16][pyarrow]

print(df)
# Salida:
#   str_col                                        int_128_col
# 0    num1  b'\\x15}\\xda\\xeb\\x18ZU\\x0fn\\x05\\x01\\x00\\x00\\x00...
# 1    num2  b'\\x08\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00...
# 2    num3  b'\\x15\\xdfp\\x81r\\x9f\\x01\\x00\\x00\\x00\\x00\\x00\\x...

print([int.from_bytes(n, byteorder="little") for n in df["int_128_col"].to_list()])
# Salida:
# [1234567898765432123456789, 8, 456789123456789]
La conclusión clave: el código de aplicación debe encargarse de estas conversiones en función de las capacidades de la biblioteca DataFrame elegida y de las compensaciones de rendimiento aceptables. Cuando no se dispone de conversiones nativas de DataFrame, los enfoques basados en Python puro siguen siendo una opción.

Formatos de lectura

Los formatos de lectura controlan los tipos de datos de los valores devueltos por los métodos query, query_np y query_df del cliente. (Los métodos raw_query y query_arrow no modifican los datos entrantes de ClickHouse, por lo que el control de formato no se aplica). Por ejemplo, si el formato de lectura de un UUID se cambia del formato native predeterminado al formato alternativo string, una consulta de ClickHouse sobre una columna UUID se devolverá como valores de cadena (usando el formato RFC 1422 estándar 8-4-4-4-12) en lugar de objetos UUID de Python. El argumento “tipo de dato” de cualquier función de formateo puede incluir comodines. El formato es una única cadena en minúsculas. Los formatos de lectura se pueden establecer en varios niveles:
  • Globalmente, usando los métodos definidos en el paquete clickhouse_connect.datatypes.format. Esto controlará el formato del tipo de dato configurado para todas las consultas.
from clickhouse_connect.datatypes.format import set_read_format

# Devolver los valores IPv6 e IPv4 como cadenas de texto
set_read_format('IPv*', 'string')

# Devolver todos los tipos Date como el segundo o día epoch subyacente
set_read_format('Date*', 'int')
  • Para una consulta completa, mediante el argumento de diccionario opcional query_formats. En ese caso, cualquier columna (o subcolumna) de los tipos de datos especificados usará el formato configurado.
# Devolver cualquier columna UUID como una cadena de texto
client.query('SELECT user_id, user_uuid, device_uuid from users', query_formats={'UUID': 'string'})
  • Para los valores de una columna específica, mediante el argumento de diccionario opcional column_formats. La clave es el nombre de la columna tal como lo devuelve ClickHouse, y el valor es el formato de la columna de datos o un diccionario “format” de segundo nivel, con un nombre de tipo de ClickHouse como clave y un valor de formatos de consulta. Este diccionario secundario se puede usar para tipos de columna anidados, como Tuples o Maps.
# Devolver los valores IPv6 de la columna `dev_address` como strings
client.query('SELECT device_id, dev_address, gw_address from devices', column_formats={'dev_address':'string'})

Opciones de formato de lectura (tipos de Python)

Tipo de ClickHouseTipo nativo de PythonFormatos de lecturaComentarios
Int[8-64], UInt[8-32]int-
UInt64intsignedActualmente, Superset no admite valores UInt64 sin signo de gran tamaño
[U]Int[128,256]intstringLos valores int de Pandas y NumPy tienen un máximo de 64 bits, por lo que pueden devolverse como cadenas
BFloat16float-Todos los float de Python son internamente de 64 bits
Float32float-Todos los float de Python son internamente de 64 bits
Float64float-
Decimaldecimal.Decimal-
StringstringbytesLas columnas String de ClickHouse no tienen una codificación inherente, por lo que también se usan para datos binarios de longitud variable
FixedStringbytesstringLos FixedString son secuencias de bytes de tamaño fijo, pero a veces se tratan como cadenas de Python
Enum[8,16]stringstring, intLos Enum de Python no aceptan cadenas vacías, por lo que todas las enumeraciones se representan como cadenas o como el valor int subyacente.
Datedatetime.dateintClickHouse almacena los valores Date como días desde el 01/01/1970. Este valor está disponible como int
Date32datetime.dateintIgual que Date, pero para un rango de fechas más amplio
DateTimedatetime.datetimeintClickHouse almacena DateTime en segundos desde la época Unix. Este valor está disponible como int
DateTime64datetime.datetimeintPython datetime.datetime está limitado a precisión de microsegundos. El valor int bruto de 64 bits está disponible
Timedatetime.timedeltaint, string, timeEl instante se guarda como una marca de tiempo Unix. Este valor está disponible como int
Time64datetime.timedeltaint, string, timePython datetime.timedelta está limitado a precisión de microsegundos. El valor int bruto de 64 bits está disponible
IPv4ipaddress.IPv4AddressstringLas direcciones IP pueden leerse como cadenas, y las cadenas con el formato correcto pueden insertarse como direcciones IP
IPv6ipaddress.IPv6AddressstringLas direcciones IP pueden leerse como cadenas, y las cadenas con el formato correcto pueden insertarse como direcciones IP
Tupledict o tupletuple, jsonLas tuplas con nombre se devuelven como diccionarios de forma predeterminada. Las tuplas con nombre también pueden devolverse como cadenas JSON
Mapdict-
NestedSequence[dict]-
UUIDuuid.UUIDstringLos UUIDs pueden leerse como cadenas con formato según RFC 4122
JSONdictstringDe forma predeterminada, se devuelve un diccionario de Python. El formato string devolverá una cadena JSON
Variantobject-Devuelve el tipo de Python correspondiente al tipo de dato de ClickHouse almacenado para el valor
Dynamicobject-Devuelve el tipo de Python correspondiente al tipo de dato de ClickHouse almacenado para el valor

Datos externos

Las consultas de ClickHouse pueden aceptar datos externos en cualquier formato de ClickHouse. Estos datos binarios se envían junto con la cadena de consulta para utilizarlos en el procesamiento de los datos. Los detalles de la funcionalidad External Data están aquí. Los métodos query* del cliente aceptan un parámetro opcional external_data para aprovechar esta funcionalidad. El valor del parámetro external_data debe ser un objeto clickhouse_connect.driver.external.ExternalData. El constructor de ese objeto acepta los siguientes argumentos:
NameTipoDescripción
file_pathstrRuta a un archivo en el sistema local desde la que se leerán los datos externos. Se requiere file_path o data
file_namestrEl nombre del “archivo” de datos externos. Si no se proporciona, se determinará a partir de file_path (sin extensiones)
databytesLos datos externos en formato binario (en lugar de leerse desde un archivo). Se requiere data o file_path
fmtstrEl formato de entrada de ClickHouse para los datos. El valor predeterminado es TSV
typesstr or seq of strUna lista de tipos de datos de las columnas de los datos externos. Si es una cadena, los tipos deben separarse por comas. Se requiere types o structure
structurestr or seq of strUna lista de nombres de columna + tipo de dato de los datos (consulte los ejemplos). Se requiere structure o types
mime_typestrTipo MIME opcional de los datos del archivo. Actualmente ClickHouse ignora este subencabezado HTTP
Para enviar una consulta con un archivo CSV externo que contiene datos de “movie” y combinar esos datos con una tabla directors ya presente en el servidor de ClickHouse:
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
Se pueden añadir archivos de datos externos adicionales al objeto ExternalData inicial mediante el método add_file, que acepta los mismos parámetros que el constructor. Para HTTP, todos los datos externos se transmiten como parte de una carga de archivos multi-part/form-data.

Zonas horarias

Existen varios mecanismos para aplicar una zona horaria a los valores DateTime y DateTime64 de ClickHouse. Internamente, el servidor ClickHouse siempre almacena cualquier objeto DateTime o DateTime64 como un número sin zona horaria que representa los segundos transcurridos desde el epoch, 1970-01-01 00:00:00 UTC. Para los valores DateTime64, la representación puede ser en milisegundos, microsegundos o nanosegundos desde el epoch, según la precisión. Como resultado, cualquier información de zona horaria se aplica siempre en el cliente. Ten en cuenta que esto implica un cálculo adicional significativo, por lo que, en aplicaciones donde el rendimiento es crítico, se recomienda tratar los tipos DateTime como timestamps epoch, salvo para la visualización y conversión para el usuario (por ejemplo, los Pandas Timestamps siempre son un entero de 64 bits que representa nanosegundos desde el epoch para mejorar el rendimiento). Al usar tipos de datos con zona horaria en las consultas, en particular el objeto datetime.datetime de Python, clickhouse-connect aplica una zona horaria en el cliente según las siguientes reglas de precedencia:
  1. Si se especifica el parámetro del método de consulta client_tzs para la consulta, se aplica la zona horaria específica de la columna
  2. Si la columna de ClickHouse tiene metadatos de zona horaria (es decir, es de un tipo como DateTime64(3, ‘America/Denver’)), se aplica la zona horaria de la columna de ClickHouse. (Ten en cuenta que estos metadatos de zona horaria no están disponibles para clickhouse-connect en las columnas DateTime anteriores a la versión 23.2 de ClickHouse)
  3. Si se especifica el parámetro del método de consulta query_tz para la consulta, se aplica la “zona horaria de la consulta”.
  4. Si se aplica una configuración de zona horaria a la consulta o a la sesión, se aplica esa zona horaria. (Esta funcionalidad aún no se ha publicado en el servidor ClickHouse)
  5. Por último, si el parámetro del cliente apply_server_timezone se ha establecido en True (el valor predeterminado), se aplica la zona horaria del servidor ClickHouse.
Ten en cuenta que, si la zona horaria aplicada según estas reglas es UTC, clickhouse-connect siempre devolverá un objeto datetime.datetime de Python sin zona horaria. Si se desea, el application code puede añadir después información adicional de zona horaria a este objeto sin zona horaria.
Última modificación el 10 de junio de 2026