Limitation de RENAME Multi-Table sur ClickHouse Cloud
Problème
ClickHouse Cloud (moteur SharedMergeTree) ne supporte pas le renommage de plusieurs tables
dans une seule instruction RENAME TABLE, ce qui est un pattern courant pour les échanges atomiques de tables
lors des migrations de schéma. ClickHouse auto-hébergé supporte cela, donc les migrations qui fonctionnent
localement ou sur des instances auto-hébergées échoueront sur ClickHouse Cloud.
Contexte / Conditions de déclenchement
- Message d'erreur :
"Database X is Shared, it does not support renaming of multiple tables in single query" - Code d'erreur : 48
- Utilisation de golang-migrate (ou similaire) avec ClickHouse Cloud
- Le SQL de migration contient un pattern comme :
RENAME TABLE db.original TO db.original_old, db.new_version TO db.original; - La migration fonctionne en staging (ClickHouse auto-hébergé) mais échoue en production (ClickHouse Cloud)
Solution
Prévention : Écrire des migrations compatibles avec ClickHouse Cloud
Au lieu d'un RENAME multi-table :
-- MAUVAIS : Cela échoue sur ClickHouse Cloud
RENAME TABLE nostr.my_table TO nostr.my_table_old,
nostr.my_table_v2 TO nostr.my_table;
Utilisez des instructions RENAME séparées :
-- BON : Diviser en opérations individuelles
RENAME TABLE nostr.my_table TO nostr.my_table_old;
RENAME TABLE nostr.my_table_v2 TO nostr.my_table;
Note : Cela perd l'atomicité, mais ClickHouse Cloud ne supporte de toute façon pas la version atomique.
Récupération : Corriger une migration défaillante qui a déjà échoué
-
Vérifier l'état actuel — identifier quelles tables existent et dans quel état elles sont :
SHOW TABLES LIKE '%my_table%'; DESCRIBE TABLE nostr.my_table; -- Vérifier si elle a l'ancien ou nouveau schéma DESCRIBE TABLE nostr.my_table_v2; -- Vérifier si la nouvelle table a été créée -
Compléter la migration manuellement avec des renommages séparés :
-- Si l'original et la v2 existent tous les deux (RENAME n'a jamais été exécuté) : RENAME TABLE nostr.my_table TO nostr.my_table_old; RENAME TABLE nostr.my_table_v2 TO nostr.my_table; DROP TABLE IF EXISTS nostr.my_table_old; -- Recréer les vues qui ont été supprimées -
Forcer la version de migration pour la marquer comme complétée :
# Utiliser golang-migrate migrate -path=/migrations -database "clickhouse://..." force VERSION -
Si vous utilisez des jobs K8s, recréer le job avec les arguments
force VERSION:containers: - name: migrate image: my-migrate-image:tag args: ["force", "65"] # Le numéro de migration qui a été appliqué manuellement
Vérification
Après la migration manuelle, vérifier :
-- Vérifier que la table a le nouveau schéma
DESCRIBE TABLE nostr.my_table;
-- Vérifier que la version de migration est propre (pas sale)
SELECT version, dirty FROM schema_migrations ORDER BY version DESC LIMIT 5;
-- Vérifier que les tables anciennes/temporaires sont nettoyées
SHOW TABLES LIKE '%my_table%';
Exemple
La migration 65 pour funnelcake devait changer view_traffic_sources.source de
Enum8 à String. La migration :
- A supprimé une vue dépendante
- A créé
view_traffic_sources_v2avec le nouveau schéma - A copié les données
- A tenté
RENAME TABLE original TO old, v2 TO original— ÉCHEC sur ClickHouse Cloud
Récupération :
# Via l'API HTTP depuis un pod curl dans le cluster :
curl -s "$CH_URL/?database=nostr&user=$USER&password=$PASS" \
--data-binary 'RENAME TABLE nostr.view_traffic_sources TO nostr.view_traffic_sources_old'
curl -s "$CH_URL/?database=nostr&user=$USER&password=$PASS" \
--data-binary 'RENAME TABLE nostr.view_traffic_sources_v2 TO nostr.view_traffic_sources'
curl -s "$CH_URL/?database=nostr&user=$USER&password=$PASS" \
--data-binary 'DROP TABLE IF EXISTS nostr.view_traffic_sources_old'
# Recréer la vue de synthèse...
# Puis forcer la version de migration à 65
Notes
- SharedMergeTree est le moteur par défaut sur ClickHouse Cloud — vous ne pouvez pas passer à un MergeTree standard
- D'autres limitations de SharedMergeTree existent (par ex., certaines opérations ALTER se comportent différemment)
- Lors de l'écriture de migrations pour des environnements à la fois auto-hébergés et cloud, utilisez toujours des instructions RENAME séparées
- Le driver ClickHouse de golang-migrate utilise
x-multi-statement=truequi divise les instructions sur;, mais le RENAME avec virgules reste une seule instruction - Si une migration échouée a laissé une table
_v2derrière elle, vous devezDROP TABLE IF EXISTSavant de relancer la migration, sinonCREATE TABLE IF NOT EXISTSignorera silencieusement la création et l'INSERT dupliquera les données dans la table v2 existante - Utilisez
SET alter_sync = 2; SET mutations_sync = 2;dans les migrations pour assurer l'exécution synchrone sur ClickHouse Cloud
Références
- Différences SharedMergeTree de ClickHouse Cloud : le moteur SharedMergeTree a des restrictions sur les opérations qui nécessitent une coordination inter-shards
- Driver ClickHouse de golang-migrate : github.com/golang-migrate/migrate avec driver clickhouse