ALTER TABLE modifient les paramètres ou les données d’une table :
La plupart des requêtes
ALTER TABLE ne sont prises en charge que pour les tables *MergeTree, Merge et Distributed.ALTER s’appliquent aux vues :
Ces instructions
ALTER modifient les entités liées au contrôle d’accès basé sur les rôles :
Combiner plusieurs actions dans un seul ALTER
Un même ALTER TABLE peut contenir plusieurs actions séparées par des virgules. Ainsi, des opérations qu’il faudrait autrement soumettre sous la forme d’une série de statements peuvent être regroupées en un seul :
ALTER, le paramètre qui régit cette attente dépend de l’action et non du statement : une action relevant du chemin d’exécution des mutations, comme MATERIALIZE INDEX, est régie par mutations_sync, tandis que les actions portant sur les métadonnées relèvent de alter_sync ; les combiner ne les soumet donc pas à un seul et même paramètre. Consultez Synchronicité des requêtes ALTER pour connaître les actions couvertes par chaque paramètre, et Combiner des clauses MATERIALIZE INDEX pour la restriction à laquelle se heurte un tel statement mixte sur une base de données Replicated.
Mutations
Les requêtesALTER destinées à modifier les données des tables sont mises en œuvre au moyen d’un mécanisme appelé « mutations », notamment ALTER TABLE … DELETE et ALTER TABLE … UPDATE. Il s’agit de processus asynchrones en arrière-plan, similaires aux fusions dans les tables MergeTree, qui produisent de nouvelles versions « mutées » des parts.
Pour les tables *MergeTree, les mutations s’exécutent en réécrivant des data parts entières.
Il n’y a pas d’atomicité — les parts sont remplacées par leurs versions mutées dès qu’elles sont prêtes, et une requête SELECT dont l’exécution a commencé pendant une mutation verra à la fois des données provenant de parts déjà mutées et de parts qui ne l’ont pas encore été.
Les mutations sont totalement ordonnées selon leur ordre de création et sont appliquées à chaque part dans cet ordre. Les mutations sont également partiellement ordonnées par rapport aux requêtes INSERT INTO : les données insérées dans la table avant la soumission de la mutation seront mutées, et celles insérées après ne le seront pas. Notez que les mutations ne bloquent en aucune façon les insertions.
Une requête de mutation renvoie immédiatement après l’ajout de l’entrée de mutation (dans le cas des tables répliquées, dans ZooKeeper ; pour les tables non répliquées, dans le système de fichiers). La mutation elle-même s’exécute de manière asynchrone en utilisant les paramètres du profil système. Pour suivre la progression des mutations, vous pouvez utiliser la table system.mutations. Une mutation soumise avec succès continuera à s’exécuter même si les serveurs ClickHouse sont redémarrés. Il n’existe aucun moyen de revenir sur une mutation une fois qu’elle a été soumise, mais si elle est bloquée pour une raison quelconque, elle peut être annulée avec la requête KILL MUTATION.
Les entrées des mutations terminées ne sont pas supprimées immédiatement (le nombre d’entrées conservées est déterminé par le paramètre du moteur de stockage finished_mutations_to_keep). Les entrées de mutation plus anciennes sont supprimées.
Coût d’exécution et achèvement
Lorsque vous planifiez unALTER TABLE, distinguez la modification des métadonnées du travail nécessaire sur les parts existantes. Le fait que le client attende ou non l’achèvement dépend de l’opération : alter_sync contrôle les opérations sur les métadonnées et MODIFY COLUMN, y compris les conversions de type qui réécrivent les données ; mutations_sync contrôle les mutations en arrière-plan telles que UPDATE, DELETE et MATERIALIZE .... Ne vous fiez pas à des durées fixes comme référence opérationnelle : le coût dépend du volume de métadonnées, des parts et des octets concernés, du coût de conversion et de la charge actuelle en arrière-plan.
Exécution synchrone des requêtes ALTER
Par défaut, les requêtesALTER sur les tables non répliquées attendent la fin de leur traitement. Avec alter_sync = 0, une requête ALTER qui effectue un traitement en arrière-plan peut rendre la main avant la fin de ce traitement. Pour les tables répliquées, la requête ajoute dans ZooKeeper les instructions correspondant aux actions appropriées, et ces actions sont ensuite exécutées dès que possible. La requête peut attendre que ces actions soient terminées sur toutes les répliques.
Pour les requêtes ALTER qui créent des mutations via le chemin d’exécution des mutations (notamment UPDATE, DELETE, MATERIALIZE INDEX, MATERIALIZE PROJECTION, MATERIALIZE COLUMN, APPLY DELETED MASK, APPLY PATCHES, CLEAR STATISTIC et MATERIALIZE STATISTIC, entre autres), le caractère synchrone est défini par le paramètre mutations_sync.
Pour les autres requêtes ALTER, y compris les réécritures MODIFY COLUMN, l’attente est contrôlée par alter_sync.
Vous pouvez spécifier, avec le paramètre replication_wait_for_inactive_replica_timeout, combien de temps (en secondes) attendre que les répliques inactives exécutent toutes les requêtes ALTER.
Pour toutes les requêtes
ALTER, si alter_sync = 2 et que certaines répliques restent inactives au-delà de la durée spécifiée par le paramètre replication_wait_for_inactive_replica_timeout, une exception UNFINISHED est levée. Avec alter_sync = 3, les répliques inactives ne font pas l’objet d’une attente, et aucune exception n’est donc levée.Attribution concurrente d’ALTER sur une même table
Sur les tables répliquées, l’envoi rapide de plusieurs statements ALTER distincts sur une même table peut échouer avec CANNOT_ASSIGN_ALTER (code 517). Le chemin de réplication déclenche cette erreur lorsque la réplique n’a pas encore appliqué certains ALTER précédents (la version des métadonnées est toujours en retard par rapport aux métadonnées communes — le serveur peut indiquer que la réplique « still not applied some of previous alters » ou « Probably too many alters executing concurrently »). Cette condition peut persister même lorsqu’un ALTER précédent a déjà été attribué. Il s’agit d’une condition générale de concurrence entre ALTER de métadonnées et mutations — elle ne se limite pas aux statements produisant uniquement des mutations. Des modifications concurrentes ordinaires des métadonnées (ADD / DROP / MODIFY et similaires) peuvent déclencher le même code pouvant donner lieu à un réessai (voir, par exemple, le chemin de réessai couvert par tests/queries/0_stateless/03518_alter_logical_race.sh).
Approches permettant d’éviter la condition de concurrence :
- Regroupez les opérations de métadonnées indépendantes dans un unique
ALTERcomportant plusieurs clauses lorsque la grammaire le permet (par exemple, plusieurs clausesADD INDEX), comme décrit dans Combiner plusieurs actions dans un seulALTER. - Sérialisez les statements
ALTERet réessayez en cas de code 517 jusqu’à ce que lesALTERprécédents aient été appliqués sur la réplique. - Pour les
ALTERproduisant des mutations, attendez la fin de la mutation précédente à l’aide d’un indicateur observable documenté, tel quemutations_syncouis_donedanssystem.mutations, avant d’envoyer la suivante.
Combinaison de clauses MATERIALIZE INDEX
Plusieurs clauses MATERIALIZE INDEX peuvent figurer dans une même instruction ALTER. Le cas couvert dans le code source consiste à regrouper plusieurs clauses ADD INDEX et les clauses MATERIALIZE INDEX correspondantes pour ces nouveaux index dans une seule instruction (voir tests/queries/0_stateless/02911_add_index_and_materialize_index.sql). Cette forme combinant ADD INDEX et MATERIALIZE INDEX mêle un segment AlterCommand à un segment MutationCommand ; DatabaseReplicated la rejette donc avec QUERY_IS_PROHIBITED (InterpreterAlterQuery::validateReplicatedDatabaseSegments). Considérez l’exemple 02911 comme valide pour les bases de données ordinaires (non-DatabaseReplicated) ; avec DatabaseReplicated, conservez les modifications de métadonnées et les mutations de matérialisation dans des instructions distinctes.
Dans l’implémentation actuelle, chaque clause MATERIALIZE INDEX est résolue par rapport à l’instantané des métadonnées de la table lors de la préparation de la mutation. Les formes à plusieurs clauses qui ne font que matérialiser des index déjà existants suivent donc le même chemin de préparation (mutation uniquement, elles restent donc dans un seul segment). Cette forme précise n’est pas encore couverte par un test stateless ciblé ; considérez-la comme un comportement de l’implémentation actuelle plutôt que comme une garantie distincte tant qu’une telle couverture n’existe pas.
Si vous avez besoin d’appliquer les mutations dans un ordre précis, vous pouvez toujours émettre une instruction MATERIALIZE INDEX par instruction et attendre avec mutations_sync.