Skip to main content

alter

ALTER

ALTER 仅支持 *MergeTreeMerge以及Distributed等引擎表。 该操作有多种形式。

列操作

改变表结构:

ALTER TABLE [db].name [ON CLUSTER cluster] ADD|DROP|CLEAR|COMMENT|MODIFY COLUMN ...

在语句中,配置一个或多个用逗号分隔的动作。每个动作是对某个列实施的操作行为。

支持下列动作:

这些动作将在下文中进行详述。

增加列

ADD COLUMN [IF NOT EXISTS] name [type] [default_expr] [codec] [AFTER name_after]

使用指定的name, type, codec 以及 default_expr (请参见 Default expressions),往表中增加新的列。

如果sql中包含 IF NOT EXISTS ,执行语句时如果列已经存在,CH不会报错。如果指定AFTER name_after(表中另一个列的名称),则新的列会加在指定列的后面。否则,新的列将被添加到表的末尾。注意,不能将新的列添加到表的开始位置, name_after 可以是执行该动作时已经在表中存在的任意列。

添加列仅仅是改变原有表的结构不会对已有数据产生影响。执行完 ALTER后磁盘中也不会出现新的数据。如果查询表时列的数据为空,那么CH会使用列的默认值来进行填充(如果有默认表达式,则使用这个;或者用0或空字符串)。当数据块完成合并(参见MergeTree)后,磁盘中会出现该列的数据。

这种方式允许 ALTER 语句能马上执行。不需要增加原有数据的大小。

示例:

ALTER TABLE visits ADD COLUMN browser String AFTER user_id

删除列

DROP COLUMN [IF EXISTS] name

通过指定 name删除列。如果语句包含 IF EXISTS,执行时遇到不存在的列也不会报错。

从文件系统中删除数据。由于是删除列的整个文件,该语句几乎是立即执行完成的。

示例:

ALTER TABLE visits DROP COLUMN browser

清空列

CLEAR COLUMN [IF EXISTS] name IN PARTITION partition_name

重置指定分区中列的值。 分区名称 partition_name 请参见 怎样设置分区表达式

如果语句中包含 IF EXISTS ,遇到不存在的列,sql执行不会报错。

示例:

ALTER TABLE visits CLEAR COLUMN browser IN PARTITION tuple()

增加注释

COMMENT COLUMN [IF EXISTS] name 'comment'

给列增加注释说明。如果语句中包含 IF EXISTS ,遇到不存在的列,sql执行不会报错。

每个列都可以包含注释。如果列的注释已经存在,新的注释会替换旧的。 注释信息保存在 DESCRIBE TABLE查询的 comment_expression 字段中。

示例:

ALTER TABLE visits COMMENT COLUMN browser 'The table shows the browser used for accessing the site.'

修改列

MODIFY COLUMN [IF EXISTS] name [type] [default_expr] [TTL]

该语句可以改变 name 列的属性:

  • Type

  • Default expression

  • TTL

有关修改列TTL的示例,请参见 Column TTL.

如果语句中包含 IF EXISTS ,遇到不存在的列,sql执行不会报错。

当改变列的类型时,列的值也被转换了,如同对列使用 toType函数一样。如果只改变了默认表达式,该语句几乎不会做任何复杂操作,并且几乎是立即执行完成的。

示例:

ALTER TABLE visits MODIFY COLUMN browser Array(String)

改变列的类型是唯一的复杂型动作 - 它改变了数据文件的内容。对于大型表,执行起来要花费较长的时间。 该操作分为如下处理步骤:

  • 为修改的数据准备新的临时文件
  • 重命名原来的文件
  • 将新的临时文件改名为原来的数据文件名
  • 删除原来的文件

仅仅在第一步是耗费时间的。如果该阶段执行失败,那么数据没有变化。如果执行后续的步骤中失败了,数据可以手动恢复。例外的情形是,当原来的文件从文件系统中被删除了,但是新的数据没有写入到临时文件中并且丢失了。

列操作的 ALTER行为是可以被复制的。这些指令会保存在ZooKeeper中,这样每个副本节点都能执行它们。所有的 ALTER 将按相同的顺序执行。 The query waits for the appropriate actions to be completed on the other replicas. 然而,改变可复制表的列是可以被中断的,并且所有动作都以异步方式执行。

ALTER 操作限制

ALTER 操作允许在嵌套的数据结构中创建和删除单独的元素(列),但是不是整个嵌套结构。添加一个嵌套数据结构的列时,你可以用类似这样的名称 name.nested_name 及类型 Array(T) 来操作。嵌套数据结构等同于 列名前带有同样前缀的多个数组列。

不支持对primary key或者sampling key中的列(在 ENGINE 表达式中用到的列)进行删除操作。改变包含在primary key中的列的类型时,如果操作不会导致数据的变化(例如,往Enum中添加一个值,或者将DateTime 类型改成 UInt32),那么这种操作是可行的。

如果 ALTER 操作不足以完成你想要的表变动操作,你可以创建一张新的表,通过 INSERT SELECT将数据拷贝进去,然后通过 RENAME将新的表改成和原有表一样的名称,并删除原有的表。你可以使用 clickhouse-copier 代替 INSERT SELECT

ALTER 操作会阻塞对表的所有读写操作。换句话说,当一个大的 SELECT 语句和 ALTER同时执行时,ALTER会等待,直到 SELECT 执行结束。与此同时,当 ALTER 运行时,新的 sql 语句将会等待。

对于不存储数据的表(例如 MergeDistributed 表), ALTER 仅仅改变了自身的表结构,不会改变从属的表结构。例如,对 Distributed 表执行 ALTER 操作时,需要对其它包含该表的服务器执行该操作。

key表达式的修改

支持下列表达式:

MODIFY ORDER BY new_expression

该操作仅支持 MergeTree 系列表 (含 replicated 表)。它会将表的 排序键变成 new_expression (元组表达式)。主键仍保持不变。

该操作是轻量级的,仅会改变元数据。

跳过索引来更改数据

该操作仅支持 MergeTree 系列表 (含 replicated 表)。 下列操作是允许的:

  • ALTER TABLE [db].name ADD INDEX name expression TYPE type GRANULARITY value [FIRST|AFTER name] - 在表的元数据中增加索引说明

  • ALTER TABLE [db].name DROP INDEX name - 从表的元数据中删除索引描述,并从磁盘上删除索引文件

由于只改变表的元数据或者删除文件,因此该操作是轻量级的,也可以被复制到其它节点(通过Zookeeper同步索引元数据)

更改约束

参见 constraints查看更多信息。

通过下面的语法,可以添加或删除约束:

ALTER TABLE [db].name ADD CONSTRAINT constraint_name CHECK expression;
ALTER TABLE [db].name DROP CONSTRAINT constraint_name;

上述语句会从表中增加或删除约束的元数据,因此会被立即处理。 对已有数据的约束检查 将不会执行

对可复制表的操作可通过Zookeeper传播到其它副本节点。

更改分区及文件块

允许进行下列关于 partitions 的操作:

分区剥离

ALTER TABLE table_name DETACH PARTITION partition_expr

将指定分区的数据移动到 detached 目录。服务器会忽略被分离的数据分区。只有当你使用 ATTACH 时,服务器才会知晓这部分数据。

示例:

ALTER TABLE visits DETACH PARTITION 201901

如何设置分区表达式章节中获取分区表达式的设置说明。

当执行操作以后,可以对 detached 目录的数据进行任意操作,例如删除文件,或者放着不管。

该操作是可以复制的,它会将所有副本节点上的数据移动到 detached 目录。注意仅能在副本的leader节点上执行该操作。想了解副本是否是leader节点,需要在 system.replicas 表执行 SELECT 操作。或者,可以很方便的在所有副本节点上执行 DETACH操作,但除leader外其它的副本节点会抛出异常。

删除分区

ALTER TABLE table_name DROP PARTITION partition_expr

从表中删除指定分区。该操作会将分区标记为不活跃的,然后在大约10分钟内删除全部数据。

如何设置分区表达式中获取分区表达式的设置说明。 该操作是可复制的,副本节点的数据也将被删除。

删除已剥离的分区|数据块

ALTER TABLE table_name DROP DETACHED PARTITION|PART partition_expr

detached目录中删除指定分区的特定部分或所有数据。访问 如何设置分区表达式可获取设置分区表达式的详细信息。

关联分区|数据块

ALTER TABLE table_name ATTACH PARTITION|PART partition_expr

detached目录中添加数据到数据表。可以添加整个分区的数据,或者单独的数据块。例如:

ALTER TABLE visits ATTACH PARTITION 201901;
ALTER TABLE visits ATTACH PART 201901_2_2_0;

访问 如何设置分区表达式可获取设置分区表达式的详细信息。

该操作是可以复制的。副本启动器检查 detached目录是否有数据。如果有,该操作会检查数据的完整性。如果一切正常,该操作将数据添加到表中。其它副本节点通过副本启动器下载这些数据。

因此可以在某个副本上将数据放到 detached目录,然后通过 ALTER ... ATTACH 操作将这部分数据添加到该表的所有副本。

从...关联分区

ALTER TABLE table2 ATTACH PARTITION partition_expr FROM table1

该操作将 table1 表的数据分区复制到 table2 表的已有分区。注意table1表的数据不会被删除。

为保证该操作能成功运行,下列条件必须满足:

  • 2张表必须有相同的结构
  • 2张表必须有相同的分区键

替换分区

ALTER TABLE table2 REPLACE PARTITION partition_expr FROM table1

该操作将 table1 表的数据分区复制到 table2表,并替换 table2表的已有分区。注意table1表的数据不会被删除。

为保证该操作能成功运行,下列条件必须满足:

  • 2张表必须有相同的结构
  • 2张表必须有相同的分区键

将分区移动到表

ALTER TABLE table_source MOVE PARTITION partition_expr TO TABLE table_dest

该操作将 table_source表的数据分区移动到 table_dest表,并删除table_source表的数据。

为保证该操作能成功运行,下列条件必须满足:

  • 2张表必须有相同的结构
  • 2张表必须有相同的分区键
  • 2张表必须属于相同的引擎系列(可复制表或不可复制表)
  • 2张表必须有相同的存储方式

清空分区的列

ALTER TABLE table_name CLEAR COLUMN column_name IN PARTITION partition_expr

重置指定分区的特定列的值。如果建表时使用了 DEFAULT 语句,该操作会将列的值重置为该默认值。

示例:

ALTER TABLE visits CLEAR COLUMN hour in PARTITION 201902

冻结分区

ALTER TABLE table_name FREEZE [PARTITION partition_expr]

该操作为指定分区创建一个本地备份。如果 PARTITION 语句省略,该操作会一次性为所有分区创建备份。

!!! 注意 "Note" 整个备份过程不需要停止服务

注意对于老式的表,可以指定分区名前缀(例如,‘2019’),然后该操作会创建所有对应分区的备份。访问 如何设置分区表达式可获取设置分区表达式的详细信息。

在执行操作的同时,对于数据快照,该操作会创建到表数据的硬链接。硬链接放置在 /var/lib/clickhouse/shadow/N/...,也就是:

  • /var/lib/clickhouse/ 服务器配置文件中指定的CH工作目录
  • N 备份的增长序号

!!! 注意 "Note" 如果你使用 多个磁盘存储数据表, 那么每个磁盘上都有 shadow/N目录,用来保存PARTITION 表达式对应的数据块。

备份内部也会创建和 /var/lib/clickhouse/ 内部一样的目录结构。该操作在所有文件上执行‘chmod’,禁止往里写入数据

当备份创建完毕,你可以从 /var/lib/clickhouse/shadow/复制数据到远端服务器,然后删除本地数据。注意 ALTER t FREEZE PARTITION操作是不能复制的,它仅在本地服务器上创建本地备份。

该操作创建备份几乎是即时的(但是首先它会等待相关表的当前操作执行完成)

ALTER TABLE t FREEZE PARTITION 仅仅复制数据, 而不是元数据信息. 要复制表的元数据信息, 拷贝这个文件 /var/lib/clickhouse/metadata/database/table.sql

从备份中恢复数据,按如下步骤操作:

  1. 如果表不存在,先创建。 查看.sql 文件获取执行语句 (将ATTACH 替换成 CREATE).
  2. 从 备份的 data/database/table/目录中将数据复制到 /var/lib/clickhouse/data/database/table/detached/目录
  3. 运行 ALTER TABLE t ATTACH PARTITION操作,将数据添加到表中

恢复数据不需要停止服务进程。 想了解备份及数据恢复的更多信息,请参见 数据备份

删除分区的索引

ALTER TABLE table_name CLEAR INDEX index_name IN PARTITION partition_expr

该操作和 CLEAR COLUMN类似,但是它重置的是索引而不是列的数据。

获取分区

ALTER TABLE table_name FETCH PARTITION partition_expr FROM 'path-in-zookeeper'

从另一服务器上下载分区数据。仅支持可复制引擎表。 该操作做了如下步骤:

  1. 从指定数据分片上下载分区。在 path-in-zookeeper 这一参数你必须设置Zookeeper中该分片的path值。
  2. 然后将已下载的数据放到 table_name 表的 detached 目录下。通过 ATTACH PARTITION|PART将数据加载到表中。

示例:

ALTER TABLE users FETCH PARTITION 201902 FROM '/clickhouse/tables/01-01/visits';
ALTER TABLE users ATTACH PARTITION 201902;

注意:

  • ALTER ... FETCH PARTITION 操作不支持复制,它仅在本地服务器上将分区移动到 detached目录。
  • ALTER TABLE ... ATTACH操作是可复制的。它将数据添加到所有副本。数据从某个副本的detached 目录中添加进来,然后添加到邻近的副本

在开始下载之前,系统检查分区是否存在以及和表结构是否匹配。然后从健康的副本集中自动选择最合适的副本。

虽然操作叫做 ALTER TABLE,但是它并不能改变表结构,也不会立即改变表中可用的数据。

移动分区|数据块

MergeTree引擎表的分区或数据块移动到另外的卷/磁盘中。参见 使用多个块设备存储数据

ALTER TABLE table_name MOVE PARTITION|PART partition_expr TO DISK|VOLUME 'disk_name'

ALTER TABLE t MOVE 操作:

  • 不支持复制,因为不同副本可以有不同的存储方式
  • 如果指定的磁盘或卷没有配置,返回错误。如果存储方式中设定的数据移动条件不能满足,该操作同样报错。
  • 这种情况也会报错:即将移动的数据已经由后台进程在进行移动操作时,并行的 ALTER TABLE t MOVE操作或者作为后台数据合并的结果。这种情形下用户不能任何额外的动作。

示例:

ALTER TABLE hits MOVE PART '20190301_14343_16206_438' TO VOLUME 'slow'
ALTER TABLE hits MOVE PARTITION '2019-09-01' TO DISK 'fast_ssd'

如何设置分区表达式

通过不同方式在 ALTER ... PARTITION 操作中设置分区表达式:

  • system.partspartition列的某个值,例如, ALTER TABLE visits DETACH PARTITION 201901
  • 表的列表达式。支持常量及常量表达式。例如, ALTER TABLE visits DETACH PARTITION toYYYYMM(toDate('2019-01-25'))
  • 使用分区ID。分区ID是字符串变量(可能的话有较好的可读性),在文件系统和ZooKeeper中作为分区名称。分区ID必须配置在 PARTITION ID中,用单引号包含,例如, ALTER TABLE visits DETACH PARTITION ID '201901'
  • ALTER ATTACH PARTDROP DETACHED PART 操作中,要配置块的名称,使用 system.detached_parts表中 name列的字符串值,例如: ALTER TABLE visits ATTACH PART '201901_1_1_0'

设置分区时,引号使用要看分区表达式的类型。例如,对于 String类型,需要设置用引号(')包含的名称。对于 DateInt*引号就不需要了。 对于老式的表,可以用数值201901 或字符串 '201901'来设置分区。新式的表语法严格和类型一致(类似于VALUES输入的解析)

上述所有规则同样适用于 OPTIMIZE 操作。在对未分区的表进行 OPTIMIZE 操作时,如果需要指定唯一的分区,这样设置表达式PARTITION tuple()。例如:

OPTIMIZE TABLE table_not_partitioned PARTITION tuple() FINAL;

ALTER ... PARTITION 操作的示例在 00502_custom_partitioning_local00502_custom_partitioning_replicated_zookeeper 提供了演示。

更改表的TTL

通过以下形式的请求可以修改 table TTL

ALTER TABLE table-name MODIFY TTL ttl-expression

ALTER操作的同步性

对于不可复制的表,所有 ALTER操作都是同步执行的。对于可复制的表,ALTER操作会将指令添加到ZooKeeper中,然后会尽快的执行它们。然而,该操作可以等待其它所有副本将指令执行完毕。

对于 ALTER ... ATTACH|DETACH|DROP操作,可以通过设置 alter_sync 来启用等待。可用参数值: 0 – 不需要等待; 1 – 仅等待自己执行(默认); 2 – 等待所有节点

Mutations

Mutations是一类允许对表的行记录进行删除或更新的ALTER操作。相较于标准的 UPDATEDELETE 用于少量行操作而言,Mutations用来对表的很多行进行重量级的操作。该操作支持 MergeTree系列表,包含支持复制功能的表。

已有的表已经支持mutations操作(不需要转换)。但是在首次对表进行mutation操作以后,它的元数据格式变得和和之前的版本不兼容,并且不能回退到之前版本。

目前可用的命令:

ALTER TABLE [db.]table DELETE WHERE filter_expr

filter_expr必须是 UInt8型。该操作将删除表中 filter_expr表达式值为非0的列

ALTER TABLE [db.]table UPDATE column1 = expr1 [, ...] WHERE filter_expr

filter_expr必须是 UInt8型。该操作将更新表中各行 filter_expr表达式值为非0的指定列的值。通过 CAST 操作将值转换成对应列的类型。不支持对用于主键或分区键表达式的列进行更新操作。

ALTER TABLE [db.]table MATERIALIZE INDEX name IN PARTITION partition_name

该操作更新 partition_name分区中的二级索引 name. 单次操作可以包含多个逗号分隔的命令。

对于 *MergeTree引擎表,mutation操作通过重写整个数据块来实现。没有原子性保证 - 被mutation操作的数据会被替换,在mutation期间开始执行的SELECT查询能看到所有已经完成mutation的数据,以及还没有被mutation替换的数据。

mutation总是按照它们的创建顺序来排序并以同样顺序在每个数据块中执行。mutation操作也会部分的和Insert操作一起排序 - 在mutation提交之前插入的数据会参与mutation操作,在mutation提交之后的插入的数据则不会参与mutation。注意mutation从来不会阻塞插入操作。

mutation操作在提交后(对于可复制表,添加到Zookeeper,对于不可复制表,添加到文件系统)立即返回。mutation操作本身是根据系统的配置参数异步执行的。要跟踪mutation的进度,可以使用系统表 system.mutations。已经成功提交的mutation操作在服务重启后仍会继续执行。一旦mutation完成提交,就不能回退了,但是如果因为某种原因操作被卡住了,可以通过 KILL MUTATION操作来取消它的执行。

已完成的mutations记录不会立即删除(要保留的记录数量由 finished_mutations_to_keep 这一参数决定)。之前的mutation记录会被删除。

修改用户

修改CH的用户账号

语法

ALTER USER [IF EXISTS] name [ON CLUSTER cluster_name]
[RENAME TO new_name]
[IDENTIFIED [WITH {PLAINTEXT_PASSWORD|SHA256_PASSWORD|DOUBLE_SHA1_PASSWORD}] BY {'password'|'hash'}]
[[ADD|DROP] HOST {LOCAL | NAME 'name' | REGEXP 'name_regexp' | IP 'address' | LIKE 'pattern'} [,...] | ANY | NONE]
[DEFAULT ROLE role [,...] | ALL | ALL EXCEPT role [,...] ]
[SETTINGS variable [= value] [MIN [=] min_value] [MAX [=] max_value] [CONST|READONLY|WRITABLE|CHANGEABLE_IN_READONLY] | PROFILE 'profile_name'] [,...]

说明

要使用 ALTER USER,你必须拥有 ALTER USER 操作的权限

Examples

设置默认角色:

ALTER USER user DEFAULT ROLE role1, role2

如果角色之前没分配给用户,CH会抛出异常。

将所有分配的角色设为默认

ALTER USER user DEFAULT ROLE ALL

如果以后给用户分配了某个角色,它将自动成为默认角色

将除了 role1role2之外的其它角色 设为默认

ALTER USER user DEFAULT ROLE ALL EXCEPT role1, role2

修改角色

修改角色.

语法

ALTER ROLE [IF EXISTS] name [ON CLUSTER cluster_name]
[RENAME TO new_name]
[SETTINGS variable [= value] [MIN [=] min_value] [MAX [=] max_value] [CONST|READONLY|WRITABLE|CHANGEABLE_IN_READONLY] | PROFILE 'profile_name'] [,...]

修改row policy

修改row policy.

语法

ALTER [ROW] POLICY [IF EXISTS] name [ON CLUSTER cluster_name] ON [database.]table
[RENAME TO new_name]
[AS {PERMISSIVE | RESTRICTIVE}]
[FOR SELECT]
[USING {condition | NONE}][,...]
[TO {role [,...] | ALL | ALL EXCEPT role [,...]}]

修改配额quotas

修改配额quotas.

语法

ALTER QUOTA [IF EXISTS] name [ON CLUSTER cluster_name]
[RENAME TO new_name]
[KEYED BY {'none' | 'user name' | 'ip address' | 'client key' | 'client key or user name' | 'client key or ip address'}]
[FOR [RANDOMIZED] INTERVAL number {SECOND | MINUTE | HOUR | DAY | WEEK | MONTH | QUARTER | YEAR}
{MAX { {QUERIES | ERRORS | RESULT ROWS | RESULT BYTES | READ ROWS | READ BYTES | EXECUTION TIME} = number } [,...] |
NO LIMITS | TRACKING ONLY} [,...]]
[TO {role [,...] | ALL | ALL EXCEPT role [,...]}]

修改settings配置

修改settings配置.

语法

ALTER SETTINGS PROFILE [IF EXISTS] name [ON CLUSTER cluster_name]
[RENAME TO new_name]
[SETTINGS variable [= value] [MIN [=] min_value] [MAX [=] max_value] [CONST|READONLY|WRITABLE|CHANGEABLE_IN_READONLY] | INHERIT 'profile_name'] [,...]