Skip to content
ClickHouse Docs
ClickHouse DocsClickHouse Docs

Insertion avancée

Insertion de données avec ClickHouse Connect : utilisation avancée

InsertContexts

ClickHouse Connect exécute les insertions au format Native, c’est-à-dire les méthodes insert et insert_df, dans un InsertContext. Les méthodes insert_arrow, insert_df_arrow et raw_insert envoient directement leurs payloads et n’en utilisent pas. L’InsertContext inclut toutes les valeurs transmises comme arguments à la méthode client insert. De plus, lors de la création initiale d’un InsertContext, ClickHouse Connect récupère les types de données des colonnes à insérer, nécessaires à des insertions efficaces au format Native. En réutilisant l’InsertContext pour plusieurs insertions, cette « pré-requête » est évitée, ce qui rend les insertions plus rapides et plus efficaces.

Il est possible d’obtenir un InsertContext à l’aide de la méthode client create_insert_context. Cette méthode prend les mêmes arguments que la fonction insert, à l’exception de context lui-même. Notez que seule la propriété data des InsertContext doit être modifiée en vue d’une réutilisation. Cela correspond à son objectif : fournir un objet réutilisable pour des insertions répétées de nouvelles données dans la même table.

test_data = [[13, "v1", "v2"], [79, "v3", "v4"]]
ic = client.create_insert_context(table="test_table", data=test_data)
client.insert(context=ic)
assert client.command("SELECT count() FROM test_table") == 2

new_data = [[101, "v5", "v6"], [113, "v7", "v8"]]
ic.data = new_data
client.insert(context=ic)
qr = client.query("SELECT * FROM test_table ORDER BY key DESC")
assert qr.row_count == 4
assert qr.first_row[0] == 113

InsertContexts incluent un état mutable mis à jour pendant le processus d’insertion ; ils ne sont donc pas thread-safe.

Formats d'écriture

Les formats d'écriture sont implémentés pour un nombre limité de types. Dans la plupart des cas, ClickHouse Connect détermine automatiquement le format d'écriture approprié pour une colonne à partir de sa première valeur de données non nulle. Par exemple, lorsque la première valeur d'une colonne DateTime est un entier, le client la traite comme un nombre de secondes depuis l'époque Unix.

Il n'est généralement pas nécessaire de remplacer un format d'écriture, mais les méthodes de clickhouse_connect.datatypes.format permettent d'en définir un globalement. Les wrappers de conteneur tels que Array, Nullable et LowCardinality conservent le comportement de mise en forme du type d'élément.

Options de format d'écriture

Type ClickHouse Type Python natif Formats d'écriture Commentaires
Int[8-64], UInt[8-32] int
UInt64 int
[U]Int[128,256] int
BFloat16 float
Float32 float
Float64 float
Decimal decimal.Decimal
String str or bytes Une colonne doit contenir de manière cohérente soit du texte, soit des octets.
FixedString bytes string Les valeurs de chaîne sont complétées par des octets nuls. Les octets vides sont écrits comme des octets tous nuls.
Enum[8,16] str or int Insérez les libellés sous forme de chaînes ou leurs valeurs entières sous-jacentes.
Date datetime.date int Les valeurs entières sont interprétées comme des jours depuis 1970-01-01.
Date32 datetime.date int Les valeurs entières sont interprétées comme des décalages signés en jours.
DateTime datetime.datetime int Les valeurs entières sont interprétées comme des secondes depuis l'époque Unix.
DateTime64 datetime.datetime int Les valeurs entières sont interprétées comme des ticks selon la précision de la colonne.
Time datetime.timedelta int, string, time Les valeurs entières sont interprétées comme des secondes.
Time64 datetime.timedelta int, string, time Les valeurs entières sont interprétées comme des ticks selon la précision de la colonne.
IPv4 ipaddress.IPv4Address string Des chaînes au format correct peuvent être insérées comme adresses IPv4
IPv6 ipaddress.IPv6Address string Des chaînes au format correct peuvent être insérées comme adresses IPv6
Tuple dict or tuple
Map dict
Nested Sequence[dict]
UUID uuid.UUID string Des chaînes au format correct peuvent être insérées comme UUID ClickHouse
JSON dict string Les dictionnaires et les chaînes contenant un objet JSON sont pris en charge. Le type legacy Object('json') n'est pas pris en charge.
Variant object Les valeurs utilisent la sérialisation native du type membre. Utilisez clickhouse_connect.datatypes.dynamic.typed_variant lorsque les types Python sont ambigus.
Dynamic object Les valeurs sont actuellement insérées à partir de leur représentation sous forme de chaîne.
QBit Sequence[float] NumPy est utilisé automatiquement pour une transposition des bits plus rapide lorsqu’il est installé.

Méthodes d’insertion spécialisées

ClickHouse Connect fournit des méthodes d’insertion spécialisées pour les formats de données courants :

  • insert_df – Insère un Pandas DataFrame comme données Native orientées colonnes. Il prend également en charge des noms/types de colonnes explicites ou un InsertContext réutilisable.
  • insert_arrow – Insère une PyArrow Table à l’aide du format d’entrée Arrow de ClickHouse.
  • insert_df_arrow – Insère un Pandas DataFrame adossé à Arrow ou un Polars DataFrame. Les colonnes Pandas doivent toutes utiliser des Dtype adossés à Arrow.

Les trois méthodes acceptent database, settings et les transport_settings HTTP par requête.

Insertion de DataFrame Pandas

import clickhouse_connect
import pandas as pd

client = clickhouse_connect.get_client()

df = pd.DataFrame({
    "id": [13, 79],
    "name": ["user_1", "user_2"],
    "age": [25, 30],
})

client.insert_df("users", df)

Insertion d’une table PyArrow

import clickhouse_connect
import pyarrow as pa

client = clickhouse_connect.get_client()

arrow_table = pa.table({
    "id": [13, 79],
    "name": ["user_1", "user_2"],
    "age": [25, 30],
})

client.insert_arrow("users", arrow_table)

Insertion d’un DataFrame adossé à Arrow (pandas 2.x)

import clickhouse_connect
import pandas as pd

client = clickhouse_connect.get_client()

# Convert to Arrow-backed dtypes for better performance
df = pd.DataFrame({
    "id": [13, 79],
    "name": ["user_1", "user_2"],
    "age": [25, 30],
}).convert_dtypes(dtype_backend="pyarrow")

client.insert_df_arrow("users", df)

Créer une table à partir d’un schéma PyArrow

create_table_from_arrow_schema génère une instruction CREATE TABLE à partir de champs scalaires Arrow courants. La correspondance couvre les entiers signés et non signés, les valeurs à virgule flottante, les booléens, les chaînes, les dates et les horodatages. Elle crée intentionnellement des colonnes ClickHouse non Nullable et lève une exception TypeError pour les types Arrow non pris en charge. Passez en revue le DDL généré avant de l’exécuter.

import clickhouse_connect
import pyarrow as pa

from clickhouse_connect.driver.ddl import create_table_from_arrow_schema

client = clickhouse_connect.get_client()
schema = pa.schema(
    [
        ("id", pa.uint32()),
        ("name", pa.string()),
        ("event_time", pa.timestamp("ms", tz="UTC")),
    ]
)
ddl = create_table_from_arrow_schema(
    table_name="arrow_events",
    schema=schema,
    engine="MergeTree",
    engine_params={"ORDER BY": "id"},
)
client.command(ddl)

Fuseaux horaires

Lors de l’insertion d’objets Python datetime dans des colonnes DateTime ou DateTime64, ClickHouse Connect les convertit en valeurs d’époque Unix.

Objets datetime avec informations de fuseau horaire

Les objets avec informations de fuseau horaire préservent l’instant représenté. Il n’est pas nécessaire que le fuseau horaire source corresponde à celui déclaré sur la colonne ClickHouse.

from datetime import datetime, timezone
from zoneinfo import ZoneInfo

client.command("CREATE TABLE events (event_time DateTime) ENGINE Memory")

data = [
    [datetime(2023, 6, 15, 10, 30, tzinfo=timezone.utc)],
    [datetime(2023, 6, 15, 10, 30, tzinfo=ZoneInfo("America/Denver"))],
    [datetime(2023, 6, 15, 10, 30, tzinfo=ZoneInfo("Asia/Tokyo"))],
]

client.insert("events", data, column_names=["event_time"])
results = client.query(
    "SELECT event_time FROM events ORDER BY event_time",
    query_tz="UTC",
    tz_mode="aware",
)
assert [row[0].hour for row in results.result_rows] == [1, 10, 16]

Objets datetime sans fuseau horaire

Le paramètre global naive_datetime_insert contrôle l'insertion d'objets Python natifs contenant des valeurs datetime sans fuseau horaire. Il s'applique également aux chaînes ISO sans fuseau horaire acceptées par les colonnes DateTime64.

  • "local" est la valeur par défaut dans la version 1.x. Python interprète la valeur dans le fuseau horaire du processus lors de l'appel à .timestamp(). Cela préserve le comportement existant.
  • "server" interprète la valeur comme une heure locale dans le fuseau horaire déclaré par la colonne DateTime ou DateTime64. Si la colonne n'a pas de fuseau horaire, le fuseau horaire du serveur communiqué lors de la connexion du client est utilisé.

Définissez l'option avant une insertion. Elle est lue lors de la sérialisation de chaque colonne d'insertion native contenant des objets Python datetime ou des chaînes ISO DateTime64 ; la modification s'applique donc aux clients existants et aux contextes d'insertion réutilisables.

from datetime import datetime

from clickhouse_connect import common

common.set_setting("naive_datetime_insert", "server")

naive_time = datetime(2023, 6, 15, 10, 30)
client.insert("events", [[naive_time]], column_names=["event_time"])

Avec "server", ClickHouse Connect associe le tzinfo cible avant de convertir la valeur en époque Unix. Pour les fuseaux horaires IANA, il suit les règles de la bibliothèque standard pour les transitions vers ou depuis l’heure d’été. En cas de chevauchement à l’automne, la valeur fold du datetime est utilisée. Par défaut, fold=0 sélectionne le décalage avant la transition, tandis que fold=1 sélectionne celui après la transition. En cas de lacune au printemps, la même sélection de décalage est utilisée, sans rejet ni normalisation.

Les heures locales inexistantes lors d’une lacune printanière peuvent ne pas effectuer d’aller-retour via un paramètre de requête en mode wall, car l’analyse de texte de ClickHouse peut sélectionner un décalage différent. Utilisez un datetime avec fuseau horaire ou une heure locale valide lorsque l’instant est important.

L’option s’applique uniquement aux insertions natives d’objets Python datetime et aux chaînes ISO sans fuseau horaire acceptées par DateTime64. Les colonnes NumPy et Pandas de type datetime64 sans fuseau horaire conservent leur conversion existante des heures locales UTC.

Pour représenter un instant précis indépendamment de l’un ou l’autre mode, associez le fuseau horaire souhaité ou fournissez explicitement un entier époque Unix.

from datetime import datetime, timezone

utc_time = datetime(2023, 6, 15, 10, 30, tzinfo=timezone.utc)
client.insert("events", [[utc_time]], column_names=["event_time"])

naive_time = datetime(2023, 6, 15, 10, 30)
epoch_timestamp = int(naive_time.replace(tzinfo=timezone.utc).timestamp())
client.insert("events", [[epoch_timestamp]], column_names=["event_time"])

Les paramètres de requête datetime sans fuseau horaire utilisent le paramètre distinct naive_datetime_binding. Son mode par défaut, "wall", envoie les champs tels quels, sans conversion vers le fuseau horaire local de l'hôte. Consultez la section Argument Parameters.

Colonnes DateTime avec métadonnées de fuseau horaire

Les colonnes ClickHouse peuvent déclarer des métadonnées de fuseau horaire, par exemple DateTime('America/Denver') ou DateTime64(3, 'Asia/Tokyo'). Ces métadonnées déterminent la manière dont les valeurs sont affichées lors de l’exécution d’une requête.

Lors de l’insertion d’une valeur avec fuseau horaire, ClickHouse Connect préserve l’instant représenté. Pour une valeur sans fuseau horaire, le paramètre naive_datetime_insert détermine si le fuseau horaire du processus ou celui de la colonne est utilisé. Lors d’une requête, le résultat utilise le fuseau horaire de la colonne, sauf si une substitution par colonne est fournie via l’argument column_tzs. L’argument query_tz ne remplace pas le fuseau horaire déclaré pour une colonne.

from datetime import datetime
from zoneinfo import ZoneInfo

client.command(
    "CREATE TABLE events_with_timezone "
    "(event_time DateTime('America/Los_Angeles')) "
    "ENGINE Memory"
)

data = datetime(2023, 6, 15, 10, 30, tzinfo=ZoneInfo("America/New_York"))
client.insert("events_with_timezone", [[data]], column_names=["event_time"])

result = client.query("SELECT event_time FROM events_with_timezone")
returned = result.first_row[0]
assert returned.hour == 7
assert returned.tzinfo == ZoneInfo("America/Los_Angeles")

Insertions de fichiers

clickhouse_connect.driver.tools.insert_file transmet en flux un fichier local vers une table existante et confie l’analyse à ClickHouse.

Paramètre Type Par défaut Description
client Client Obligatoire Client synchrone utilisé pour l’insertion.
table str Obligatoire Table cible simple ou qualifiée par la base de données.
file_path str Obligatoire Chemin local vers le fichier d’entrée.
fmt str "CSV" ou "CSVWithNames" Format d’entrée. Par défaut, "CSV" lorsque column_names est fourni, et "CSVWithNames" sinon.
column_names Sequence[str] None Colonnes représentées par le fichier. Non requis pour les formats qui incluent les noms.
database str None Base de données cible lorsque la table n’est pas qualifiée.
settings dict None Voir l’argument Settings.
compression str None Compression existante du fichier, telle que "zstd", "lz4" ou "gzip". gzip est inféré à partir des noms de fichier .gz et .gzip.

Les paramètres du format d’entrée, tels que input_format_allow_errors_ratio et input_format_allow_errors_num, peuvent être transmis via settings.

import clickhouse_connect

from clickhouse_connect.driver.tools import insert_file

client = clickhouse_connect.get_client()
insert_file(
    client,
    "example_table",
    "my_data.csv",
    settings={
        "input_format_allow_errors_ratio": 0.2,
        "input_format_allow_errors_num": 5,
    },
)

Pour un AsyncClient, utilisez await avec insert_file_async en passant les mêmes arguments :

from clickhouse_connect.driver.tools import insert_file_async

await insert_file_async(async_client, "example_table", "my_data.csv")

L'utilitaire asynchrone lit le fichier dans un thread worker avant d'attendre raw_insert, de sorte que le contenu du fichier reste en mémoire.

Navigation