Skip to main content
大多数 ALTER TABLE 查询都会修改表设置或数据:
大多数 ALTER TABLE 查询仅适用于 *MergeTreeMergeDistributed 表。
这些 ALTER 语句用于操作视图: 这些 ALTER 语句用于修改与基于角色的访问控制相关的实体:

变更

用于修改表数据的 ALTER 查询,是通过一种称为“变更”的机制实现的,最典型的就是 ALTER TABLE … DELETEALTER TABLE … UPDATE。它们是异步后台进程,类似于 MergeTree 表中的合并,用于生成新的“mutated”版本的 parts。 对于 *MergeTree 表,变更是通过重写整个数据分区片段来执行的。 它不具备原子性——变更后的 parts 一旦准备就绪,就会立即替换原来的 parts;而在变更执行期间开始的 SELECT 查询,既会看到已经变更过的 parts 中的数据,也会看到尚未变更的 parts 中的数据。 变更按照创建顺序完全有序,并按该顺序应用到每个 part。变更与 INSERT INTO 查询之间也存在部分顺序关系:在变更提交之前插入到表中的数据会被变更,而在此之后插入的数据则不会被变更。请注意,变更不会以任何方式阻塞插入。 变更查询在变更条目添加完成后会立即返回 (对于复制表,会添加到 ZooKeeper;对于非复制表,则会添加到文件系统) 。变更本身会使用系统 profile 设置异步执行。要跟踪变更的进度,可以使用 system.mutations 表。成功提交的变更即使在 ClickHouse 服务器重启后也会继续执行。变更一旦提交,就无法回滚;但如果由于某种原因卡住了,可以使用 KILL MUTATION 查询将其取消。 已完成变更的条目不会立即删除 (保留条目的数量由存储引擎参数 finished_mutations_to_keep 决定) 。较早的变更条目会被删除。

ALTER 查询的同步性

对于非复制表,所有 ALTER 查询都会同步执行。对于复制表,查询只会将相应操作的指令添加到 ZooKeeper 中,而这些操作本身会尽快执行。不过,查询也可以等待,直到所有副本都完成这些操作。 对于会创建变更的 ALTER 查询 (例如但不限于 UPDATEDELETEMATERIALIZE INDEXMATERIALIZE PROJECTIONMATERIALIZE COLUMNAPPLY DELETED MASKAPPLY PATCHESCLEAR STATISTICMATERIALIZE STATISTIC) ,其同步方式由 mutations_sync 设置决定。 对于其他仅修改元数据的 ALTER 查询,可以使用 alter_sync 设置来配置等待行为。 你可以使用 replication_wait_for_inactive_replica_timeout 设置,指定等待非活动副本执行完所有 ALTER 查询的时长 (以秒为单位) 。
对于所有 ALTER 查询,如果 alter_sync = 2,且某些副本处于非活动状态的时间超过 replication_wait_for_inactive_replica_timeout 设置中指定的时长,则会抛出 UNFINISHED 异常。

单张表上的并发 ALTER 分配

在复制表上,短时间内连续对同一张表提交多条独立的 ALTER 语句,可能会因 CANNOT_ASSIGN_ALTER (代码 517) 而失败。当副本尚未应用此前的某些 ALTER (元数据版本仍落后于共享元数据——服务器可能提示副本“still not applied some of previous alters”或“Probably too many alters executing concurrently”) 时,复制路径会引发此错误。即使较早的 ALTER 已被分配,这种情况仍可能持续存在。这是一种通用的并发元数据 ALTER / 变更情况,并不局限于仅产生变更的语句。常规的并发元数据修改 (ADD / DROP / MODIFY 等) 同样可能引发这一可重试错误代码 (例如,参见 tests/queries/0_stateless/03518_alter_logical_race.sh 覆盖的重试路径) 。 避免此竞争条件的方法:
  • 在语法允许的情况下,将独立的元数据操作合并为单条包含多个子句的 ALTER (例如多个 ADD INDEX 子句) 。
  • ALTER 语句串行执行;遇到代码 517 时重试,直到副本应用了此前的 ALTER
  • 对于会产生变更的 ALTER,请在提交下一条语句前,通过已文档化的可观测项 (如 mutations_syncsystem.mutations 中的 is_done) 等待此前的变更完成。

合并 MATERIALIZE INDEX 子句

一条 ALTER 语句中可以包含多个 MATERIALIZE INDEX 子句。代码库中已覆盖的场景是:在一条语句中,将多个 ADD INDEX 子句与针对同一批新索引的 MATERIALIZE INDEX 一并使用 (参见 tests/queries/0_stateless/02911_add_index_and_materialize_index.sql) 。这种组合的 ADD INDEX + MATERIALIZE INDEX 形式同时包含 AlterCommand 片段和 MutationCommand 片段,因此 DatabaseReplicated 会拒绝该语句,并返回 QUERY_IS_PROHIBITED (InterpreterAlterQuery::validateReplicatedDatabaseSegments) 。02911 示例适用于普通 (非 DatabaseReplicated) 数据库;对于 DatabaseReplicated,请将元数据变更和物化变更拆分为不同的语句。 在当前实现中,准备变更时,每个 MATERIALIZE INDEX 子句都会根据表元数据快照进行解析。因此,针对已有索引、仅包含物化操作的多子句形式也会遵循相同的准备路径 (仅包含变更操作,因此仍位于同一个片段内) 。这种确切形式尚未有专门的无状态测试覆盖;在具备此类测试覆盖前,应将其视为当前实现行为,而非单独保证的契约。 如果需要按顺序应用变更,仍可在每条语句中执行一个 MATERIALIZE INDEX,并通过 mutations_sync 等待。
最后修改于 2026年8月14日