FORMAT Native gestionado por el client, lo que abarca query, query_np, query_df, sus variantes de streaming por bloques y por filas, y los inserts, incluido insert_df. Los métodos de Arrow usan FORMAT Arrow y no se ven afectados, al igual que las consultas sin procesar, los inserts sin procesar y los formatos que no son Native.
El códec es experimental y de uso opcional. El códec de Python sigue siendo el predeterminado.
Instalación
El códec compilado se distribuye como un paquete wheel independiente llamadoclickhouse-connect-core, que proporciona el módulo de extensión _ch_core. Instale el códec junto con las integraciones que use su aplicación:
query_np, query_df, sus variantes de streaming y query(..., use_numpy=True). Las consultas de NumPy no requieren Pandas. Agregue el extra async para usar el Client asíncrono.
PyArrow sigue siendo necesario para los métodos de Arrow y para el almacenamiento de Pandas basado en Arrow. Instale el extra arrow para usar estas funcionalidades:
mode.string_storage de Pandas. Cuando PyArrow está instalado, las cadenas usan la conversión de Arrow existente, con validación completa de UTF-8, con cualquiera de los dos backends de almacenamiento. Sin PyArrow, el driver usa la conversión de objetos de Rust y el almacenamiento predeterminado de Pandas usa cadenas de Python. Si se solicita explícitamente el almacenamiento de cadenas de Arrow sin PyArrow, se lanza un error de dependencia. El UTF-8 no válido mantiene la representación hexadecimal existente con cualquiera de los dos backends de almacenamiento.
El códec, su empaquetado y su conjunto de dependencias son experimentales. La conversión directa de búfer ahora admite columnas no Nullable de enteros de 8 a 64 bits, Float32/64, Boolean, BFloat16, Interval, Date, Date32, DateTime y DateTime64. Las columnas escalares Time y Time64, incluidos los valores Nullable, también usan búferes directos, al igual que BFloat16 Nullable y la salida extendida de Pandas de enteros, flotantes e Interval Nullable. BFloat16 conserva la salida float32 y su política actual de valores faltantes Float32 de Pandas. Los valores Interval siguen siendo recuentos con signo en su unidad declarada. La conversión temporal conserva las unidades declaradas y las reglas de zona horaria existentes. Los alias Nullable de SimpleAggregateFunction de Time64 ahora devuelven duraciones correctas y NaT para los valores NULL. Las columnas escalares Nullable DateTime64(9) también usan búferes para preservar los nanosegundos en la salida de NumPy y Pandas. Las demás fechas y marcas de tiempo Nullable mantienen sus rutas de conversión de objetos.
Los arrays de Time/Time64, incluidos los arrays anidados y las hojas Nullable, y LowCardinality(Time), incluidos los valores Nullable, también usan búferes directos. Su anidamiento, sus unidades de duración y su representación de valores nulos no cambian. LowCardinality(Time64) sigue sin ser compatible con el núcleo de Rust.
Para las columnas escalares Nullable DateTime64(9), query_df y query_df_stream preservan los nueve dígitos fraccionarios, incluso a través de alias de SimpleAggregateFunction. En Pandas 3, las columnas de fecha y hora de la salida predeterminada ahora usan unidades de nanosegundos en lugar de microsegundos. La inferencia actual del dtype object para bloques compuestos íntegramente por NULL no cambia. Si una zona horaria con nombre situara un valor fuera del rango de nanosegundos de Pandas, esa columna mantiene su conversión de objetos y su comportamiento de rango anteriores.
Para estas columnas, los campos de objeto de query_np y query_np_stream ahora contienen celdas numpy.datetime64 en lugar de celdas datetime de Python, con None para los NULL de SQL. Los valores de zonas con nombre usan ticks UTC sin metadata de zona horaria, igual que el códec de Python. Así se preservan los nanosegundos sin necesidad de Pandas. Use query_df si necesita marcas de tiempo con zona horaria. Los demás tipos de celdas temporales Nullable de NumPy no cambian.
Las consultas escalares DateTime64 de NumPy y Pandas rechazan con ProgrammingError las precisiones distintas de 0, 3, 6 y 9, incluidas las columnas Nullable y los alias de SimpleAggregateFunction.
Si se selecciona un códec de Rust y el módulo compilado no está instalado, la creación del Client lanza un NotSupportedError que indica este comando de instalación.
Habilitar el códec
Seleccione el códec con la opción de clientnative_codec:
El valor predeterminado también puede definirse mediante el common setting
native_codec o la environment variable CLICKHOUSE_CONNECT_NATIVE_CODEC. El orden de precedencia es: primero el keyword argument del client, luego el common setting y, por último, la environment variable.
Esta opción se ignora en los clients con interface="chdb", que siempre usan el códec de Python.
Cuándo usar el códec de Rust
El códec de Rust resulta más útil para resultados de DataFrame grandes con tipos de texto, de contenedor y complejos, comoString, LowCardinality, Map, Array, JSON, Decimal y UUID. También puede beneficiar a streams de bloques grandes de filas y columnas, a cargas de trabajo con consultas concurrentes y a inserciones masivas.
En resultados pequeños y consultas limitadas por la red, la diferencia puede ser mínima. Los resultados numéricos planos ya utilizan rutas masivas eficientes en el códec de Python, por lo que el beneficio también puede ser menor.
Los búferes directos evitan arrays intermedios de Arrow para los tipos compatibles. El ensamblado final de resultados de NumPy y Pandas aún puede reservar memoria y copiar datos, por lo que esto no hace que todos los resultados de consultas sean zero-copy.
Sin PyArrow, la conversión de cadenas en Rust construye objetos de cadena de Python a partir de cada bloque decodificado. Con los tamaños de bloque predeterminados, el pico de memoria para resultados grandes de tipo String es similar al del códec de Python. Los bloques muy grandes, como un único bloque que contiene un millón de filas, mantienen en memoria todo el bloque decodificado mientras se construyen sus cadenas y pueden alcanzar un pico de memoria mayor que el del códec de Python. Para resultados grandes de Pandas con StringDtype, instala el extra arrow y usa el almacenamiento de cadenas de Arrow. Pandas 3 selecciona el almacenamiento de Arrow de forma predeterminada cuando PyArrow está instalado. Pandas 2 requiere pd.options.mode.string_storage = "pyarrow".
Las llamadas a query() almacenadas temporalmente en el búfer sobre resultados muy anchos o totalmente numéricos pueden ser, por ahora, más lentas y consumir más memoria máxima con el códec de Rust. Para esas cargas de trabajo, es preferible usar query_df, query_row_block_stream o query_column_block_stream. Para NumPy y Pandas, query_np_stream y query_df_stream también pueden reducir el pico de memoria. Procesa y libera cada bloque en lugar de acumular todo el stream. El uso de memoria sigue dependiendo del tamaño de cada bloque, por lo que hacer streaming de un único bloque grande no ofrece la misma ventaja.
Haz un benchmark de tu propia carga de trabajo antes de adoptar el códec. Usa native_codec="rust_strict" mientras mides, de modo que una opción no soportada o una dependencia faltante lance un error en lugar de redirigir silenciosamente la consulta a Python.
Reglas de fallback
Las decisiones de fallback se toman antes de leer o enviar ningún byte, por lo que nunca se produce un cambio de códec a mitad del stream. En las queries, la elección ocurre antes de consumir el response body. En los inserts, el codificador de Rust solo se selecciona cuando todos los tipos de columna son compatibles; de lo contrario, todo el insert se ejecuta con el códec de Python. Cuandonaive_datetime_insert="server" está activo, rust deriva al códec de Python cualquier insert que contenga alguna columna DateTime o DateTime64, de modo que se aplique el timezone declarado de la columna o el server timezone. rust_strict rechaza esa combinación. El modo predeterminado naive_datetime_insert="local" sigue utilizando el codificador de Rust.
Las queries de metadata internas del driver, incluidas las sentencias de reflection del dialect de SQLAlchemy, siempre usan el códec de Python, de forma silenciosa, en todos los modos.
Los payloads Native malformados que detecta el códec de Rust generan DataError.
Control de versiones
clickhouse-connect-core se versiona de forma independiente de clickhouse-connect. El extra rust requiere clickhouse-connect-core>=0.2.1,<0.3. El driver comprueba tanto la versión de la API de vinculación como la capacidad de búfer de columnas cuando se selecciona un códec de Rust. El wheel publicado de core 0.2.0 no incluye la capacidad de búfer de columnas. Si el wheel instalado es incompatible, la creación del Client lanza un NotSupportedError tanto para rust como para rust_strict, con este comando de upgrade:
clickhouse-connect-core y pueden incorporarse actualizando a un wheel de core compatible. Los cambios en la integración de Rust del driver requieren actualizar clickhouse-connect.
Diferencias de comportamiento conocidas
El códec de Rust busca la paridad celda a celda con el códec de Python. Se conocen las siguientes diferencias.- Los resultados de
query_npyquery_dfpara columnasVariantcontienen objetos Python simples en lugar de valores escalares de numpy. Los valores son iguales, pero los tipos de celda difieren. - Los valores
Dynamicque contienenTime64se materializan comodatetime.timedeltaen los resultados dequery_npyquery_dfde Rust. Con las escalas 0, 3, 6 y 9, los valores coinciden con las celdasnumpy.timedelta64del códec de Python, pero los tipos de celda difieren. En las demás escalas, el códec de Rust devuelvedatetime.timedelta, mientras que el de Python lanzaProgrammingErrorporque NumPy no dispone de una unidad equivalente. La metadata de los miembros de Dynamic no se expone al driver tras la decodificación en Rust, por lo que conviene usarnative_codec="python"cuando se necesiten tipos de celda de NumPy o la validación de escalas no admitidas. - En
query_df, el códec de Python puede convertir a cadena los valores compuestos almacenados en los shared data de JSON. El códec de Rust devuelve objetos decodificados, lo que coincide con los resultados dequery_npde ambos códecs. - Una alternativa
LowCardinalitydentro de un contenedor que se materializa por celda, comoArray(Variant(...)), produce celdas con valores iguales que no comparten la identidad de objeto por slot de diccionario que sí presenta el códec de Python. - Las columnas
Nullable(Tuple(...))con uno o más elementos se decodifican correctamente con el códec de Rust. El códec de Python interpreta mal este layout, por lo que el resultado de Rust es el comportamiento de referencia. Ambos códecs admitenNullable(Tuple()). rust_strictrechaza las opciones de consulta que la ruta de Rust no implementa, como losquery_formatspersonalizados por consulta, en lugar de alterar el comportamiento de forma silenciosa.- Los errores de conversión y validación en las inserciones de Rust pueden lanzar
DataErrorallí donde el códec de Python lanzaValueError, y el texto del mensaje puede diferir. Algunos ejemplos son valoresTimeyTime64inválidos, direcciones IPv6, dimensiones de QBit, longitudes deFixedString, cadenasFloat64e intentos de insertar elementos en una columnaTuple(). - El codificador de Rust rechaza
b""paraFixedString(N)y cadenas numéricas como"2"en columnas de enteros. El códec de Python rellena con ceros un valorFixedStringvacío y convierte las cadenas numéricas. - El códec de Rust decodifica algunos valores de variantes compartidas de
Dynamica sus tipos de Python cuando el códec de Python deja el valor como bytes sin procesar. Por ejemplo, unDecimalalmacenado puede devolverse comodecimal.Decimaldesde Rust y como un valor binario desde Python. - En el caso de los valores
Dateen el almacenamiento compartido deDynamic,query_npyquery_dfdevuelven celdasdatetime.datecon el códec de Rust y celdasnumpy.datetime64con el códec de Python. Ambos códecs devuelvendatetime.datedesdequery.