Passer au contenu principal

Cas 1 : INSERT dans une partition d’une table de la famille MergeTree*

Cette opération est transactionnelle (ACID) si les lignes insérées sont compactées et insérées sous la forme d’un seul bloc (voir les remarques) :
  • Atomicité : un INSERT réussit ou est rejeté dans son ensemble : si une confirmation est envoyée au client, toutes les lignes ont été insérées ; si une erreur est envoyée au client, aucune ligne n’a été insérée.
  • Cohérence : si aucune contrainte de table n’est violée, toutes les lignes d’un INSERT sont insérées et l’INSERT réussit ; si des contraintes sont violées, aucune ligne n’est insérée.
  • Isolation : les clients concurrents observent un instantané cohérent de la table — soit l’état de la table tel qu’il était avant la tentative d’INSERT, soit l’état après la réussite de l’INSERT ; aucun état partiel n’est visible. Les clients à l’intérieur d’une autre transaction bénéficient de l’isolation par instantané, tandis que les clients en dehors d’une transaction ont un niveau d’isolation lecture non validée.
  • Durabilité : un INSERT réussi est écrit dans le système de fichiers avant qu’une réponse ne soit renvoyée au client, sur une seule réplique ou sur plusieurs répliques (contrôlé par le paramètre insert_quorum), et ClickHouse peut demander à l’OS de synchroniser les données du système de fichiers sur le support de stockage (contrôlé par le paramètre fsync_after_insert).
  • Un INSERT dans plusieurs tables avec une seule instruction est possible si des vues matérialisées sont impliquées (l’INSERT du client vise une table à laquelle des vues matérialisées sont associées).

Cas 2 : INSERT dans plusieurs partitions d’une table de la famille MergeTree*

Identique au cas 1 ci-dessus, avec cette précision :
  • Si la table comporte de nombreuses partitions et que l’INSERT en couvre plusieurs, alors l’insertion dans chaque partition constitue à elle seule une transaction

Cas 3 : INSERT dans une table distribuée de la famille MergeTree*

Identique au cas 1 ci-dessus, avec ce détail :
  • l’INSERT dans une table Distributed n’est pas transactionnel dans son ensemble, tandis que l’insertion dans chaque segment l’est

Cas 4 : Utiliser une table Buffer

  • les insertions dans les tables Buffer ne sont ni atomiques, ni isolées, ni cohérentes, ni durables

Cas 5 : utilisation de async_insert

Identique au cas 1 ci-dessus, avec ce détail :
  • l’atomicité est garantie même si async_insert est activé et que wait_for_async_insert est défini sur 1 (par défaut), mais si wait_for_async_insert est défini sur 0, alors l’atomicité n’est pas garantie.

Remarques

  • les lignes insérées depuis le client dans un certain format de données sont regroupées dans un seul bloc lorsque :
    • le format d’insertion est basé sur les lignes (comme CSV, TSV, Values, JSONEachRow, etc.) et que les données contiennent moins de max_insert_block_size lignes (~1 000 000 par défaut) ou moins de min_chunk_bytes_for_parallel_parsing octets (10 Mo par défaut) si le parsing parallèle est utilisé (activé par défaut)
    • le format d’insertion est basé sur les colonnes (comme Native, Parquet, ORC, etc.) et que les données ne contiennent qu’un seul bloc de données
  • la taille du bloc inséré peut généralement dépendre de nombreux paramètres (par exemple : max_block_size, max_insert_block_size, min_insert_block_size_rows, min_insert_block_size_bytes, preferred_block_size_bytes, etc.)
  • si le client n’a pas reçu de réponse du serveur, il ne sait pas si la transaction a abouti et peut répéter la transaction en s’appuyant sur les garanties d’insertion exactly-once
  • ClickHouse utilise en interne MVCC avec isolation par instantané pour les transactions concurrentes
  • toutes les propriétés ACID restent valides même en cas d’arrêt forcé ou de crash du serveur
  • il faut activer soit insert_quorum sur différentes AZ, soit fsync afin de garantir la durabilité des insertions dans une configuration typique
  • la « cohérence » au sens d’ACID ne couvre pas la sémantique des systèmes distribués, voir https://jepsen.io/consistency ; cet aspect est contrôlé par d’autres paramètres (select_sequential_consistency)
  • cette explication ne couvre pas la nouvelle fonctionnalité de transactions, qui permet d’avoir des transactions complètes sur plusieurs tables, des vues matérialisées, pour plusieurs SELECT, etc. (voir la section suivante sur Transactions, Commit, and Rollback)

Transactions, commit et rollback

Outre les fonctionnalités décrites au début de ce document, ClickHouse prend en charge, à titre expérimental, les transactions, les commits et les rollbacks.

Prérequis

  • Déployez ClickHouse Keeper ou ZooKeeper pour suivre les transactions
  • DB atomic uniquement (par défaut)
  • Uniquement le moteur de table MergeTree non répliqué
  • Activez la prise en charge expérimentale des transactions en ajoutant ce paramètre dans config.d/transactions.xml :
    <clickhouse>
      <allow_experimental_transactions>1</allow_experimental_transactions>
    </clickhouse>
    

Remarques

  • Il s’agit d’une fonctionnalité expérimentale et des modifications sont à prévoir.
  • Si une exception se produit pendant une transaction, vous ne pouvez pas valider la transaction. Cela inclut toutes les exceptions, y compris les exceptions UNKNOWN_FUNCTION causées par des fautes de frappe.
  • Les transactions imbriquées ne sont pas prises en charge ; terminez la transaction en cours et démarrez-en une nouvelle

Configuration

Ces exemples s’appuient sur un ClickHouse server mono-nœud avec ClickHouse Keeper activé.

Activer la prise en charge expérimentale des transactions

/etc/clickhouse-server/config.d/transactions.xml
<clickhouse>
    <allow_experimental_transactions>1</allow_experimental_transactions>
</clickhouse>

Configuration de base pour un seul nœud ClickHouse server avec ClickHouse Keeper activé

Consultez la documentation sur le déploiement pour plus de détails sur le déploiement de ClickHouse server et sur un quorum adéquat de nœuds ClickHouse Keeper. La configuration présentée ici est fournie à titre expérimental.
/etc/clickhouse-server/config.d/config.xml
<clickhouse replace="true">
    <logger>
        <level>debug</level>
        <log>/var/log/clickhouse-server/clickhouse-server.log</log>
        <errorlog>/var/log/clickhouse-server/clickhouse-server.err.log</errorlog>
        <size>1000M</size>
        <count>3</count>
    </logger>
    <display_name>node 1</display_name>
    <listen_host>0.0.0.0</listen_host>
    <http_port>8123</http_port>
    <tcp_port>9000</tcp_port>
    <zookeeper>
        <node>
            <host>clickhouse-01</host>
            <port>9181</port>
        </node>
    </zookeeper>
    <keeper_server>
        <tcp_port>9181</tcp_port>
        <server_id>1</server_id>
        <log_storage_path>/var/lib/clickhouse/coordination/log</log_storage_path>
        <snapshot_storage_path>/var/lib/clickhouse/coordination/snapshots</snapshot_storage_path>
        <coordination_settings>
            <operation_timeout_ms>10000</operation_timeout_ms>
            <session_timeout_ms>30000</session_timeout_ms>
            <raft_logs_level>information</raft_logs_level>
        </coordination_settings>
        <raft_configuration>
            <server>
                <id>1</id>
                <hostname>clickhouse-keeper-01</hostname>
                <port>9234</port>
            </server>
        </raft_configuration>
    </keeper_server>
</clickhouse>

Exemple

Vérifiez que les transactions expérimentales sont activées

Exécutez un BEGIN TRANSACTION ou un START TRANSACTION, puis un ROLLBACK, afin de vérifier que les transactions expérimentales sont activées et que ClickHouse Keeper l’est également, car il sert à suivre les transactions.
BEGIN TRANSACTION
Ok.
Si l’erreur suivante s’affiche, vérifiez votre fichier de configuration pour vous assurer que allow_experimental_transactions est défini sur 1 (ou sur toute autre valeur que 0 ou false).
Code: 48. DB::Exception: Received from localhost:9000.
DB::Exception: Transactions are not supported.
(NOT_IMPLEMENTED)
Vous pouvez également vérifier ClickHouse Keeper en exécutant :
echo ruok | nc localhost 9181
ClickHouse Keeper doit répondre par imok.
ROLLBACK
Ok.

Créer une table de test

La création de tables n’est pas transactionnelle. Exécutez cette requête DDL en dehors de toute transaction.
CREATE TABLE mergetree_table
(
    `n` Int64
)
ENGINE = MergeTree
ORDER BY n
Ok.

Démarrer une transaction et insérer une ligne

BEGIN TRANSACTION
Ok.
INSERT INTO mergetree_table FORMAT Values (10)
Ok.
SELECT *
FROM mergetree_table
┌──n─┐
│ 10 │
└────┘
Vous pouvez interroger la table dans une transaction et constater que la ligne a été insérée même si elle n’a pas encore été validée.

Annulez la transaction, puis interrogez de nouveau la table

Vérifiez que la transaction a bien été annulée :
ROLLBACK
Ok.
SELECT *
FROM mergetree_table
Ok.

0 rows in set. Elapsed: 0.002 sec.

Finaliser une transaction et interroger à nouveau la table

BEGIN TRANSACTION
Ok.
INSERT INTO mergetree_table FORMAT Values (42)
Ok.
COMMIT
Ok. Elapsed: 0.002 sec.
SELECT *
FROM mergetree_table
┌──n─┐
│ 42 │
└────┘

Introspection des transactions

Vous pouvez inspecter les transactions en interrogeant la table system.transactions, mais notez que vous ne pouvez pas interroger cette table depuis une session déjà engagée dans une transaction. Ouvrez une deuxième session clickhouse client pour interroger cette table.
SELECT *
FROM system.transactions
FORMAT Vertical
Row 1:
──────
tid:         (33,61,'51e60bce-6b82-4732-9e1d-b40705ae9ab8')
tid_hash:    11240433987908122467
elapsed:     210.017820947
is_readonly: 1
state:       RUNNING

Plus de détails

Consultez ce ticket récapitulatif pour accéder à des tests bien plus complets et suivre l’avancement.
Dernière modification le 29 juin 2026