列操作
一组允许更改表结构的查询。
语法
ALTER [TEMPORARY] TABLE [db].name [ON CLUSTER cluster] ADD|DROP|RENAME|CLEAR|COMMENT|{MODIFY|ALTER}|MATERIALIZE COLUMN ...
在查询中,指定一个或多个以逗号分隔的操作列表。每个操作都是对列进行的操作。
支持以下操作
- 添加列 (ADD COLUMN) — 向表中添加新列。
- 删除列 (DROP COLUMN) — 删除列。
- 重命名列 (RENAME COLUMN) — 重命名现有列。
- 清空列 (CLEAR COLUMN) — 重置列值。
- 添加列注释 (COMMENT COLUMN) — 向列添加文本注释。
- 修改列 (MODIFY COLUMN) — 更改列的类型、默认表达式、TTL 和列设置。
- 移除列属性 (MODIFY COLUMN REMOVE) — 删除列的某个属性。
- 修改列设置 (MODIFY COLUMN MODIFY SETTING) - 更改列设置。
- 重置列设置 (MODIFY COLUMN RESET SETTING) - 重置列设置。
- 物化列 (MATERIALIZE COLUMN) — 在缺少该列的数据块中物化该列。下面将详细介绍这些操作。
添加列 (ADD COLUMN)
ADD COLUMN [IF NOT EXISTS] name [type] [default_expr] [codec] [AFTER name_after | FIRST]
使用指定的 name
、type
、codec
和 default_expr
(参见 默认表达式 部分)向表中添加新列。
如果包含 IF NOT EXISTS
子句,如果列已存在,则查询不会返回错误。如果指定 AFTER name_after
(另一列的名称),则该列将添加到表列列表中指定列之后。如果要将列添加到表的开头,请使用 FIRST
子句。否则,该列将添加到表的末尾。对于一系列操作,name_after
可以是之前操作中添加的列的名称。
添加列只会更改表结构,而不会对数据执行任何操作。ALTER
后数据不会出现在磁盘上。如果在从表中读取数据时缺少列的数据,则会使用默认值填充(如果存在默认表达式,则执行默认表达式,或者使用零或空字符串)。在合并数据块后(参见 MergeTree),该列将出现在磁盘上。
这种方法允许我们立即完成 ALTER
查询,而不会增加旧数据量。
示例
ALTER TABLE alter_test ADD COLUMN Added1 UInt32 FIRST;
ALTER TABLE alter_test ADD COLUMN Added2 UInt32 AFTER NestedColumn;
ALTER TABLE alter_test ADD COLUMN Added3 UInt32 AFTER ToDrop;
DESC alter_test FORMAT TSV;
Added1 UInt32
CounterID UInt32
StartDate Date
UserID UInt32
VisitID UInt32
NestedColumn.A Array(UInt8)
NestedColumn.S Array(String)
Added2 UInt32
ToDrop UInt32
Added3 UInt32
删除列 (DROP COLUMN)
DROP COLUMN [IF EXISTS] name
删除名称为 name
的列。如果指定了 IF EXISTS
子句,则如果列不存在,则查询不会返回错误。
从文件系统中删除数据。由于这会删除整个文件,因此查询几乎会立即完成。
如果 物化视图 引用了某个列,则无法删除该列。否则,将返回错误。
示例
ALTER TABLE visits DROP COLUMN browser
重命名列 (RENAME COLUMN)
RENAME COLUMN [IF EXISTS] name to new_name
将列 name
重命名为 new_name
。如果指定了 IF EXISTS
子句,则如果列不存在,则查询不会返回错误。由于重命名不涉及底层数据,因此查询几乎会立即完成。
**注意**:表键表达式(使用 ORDER BY
或 PRIMARY KEY
)中指定的列不能重命名。尝试更改这些列将产生 SQL 错误 [524]
。
示例
ALTER TABLE visits RENAME COLUMN webBrowser TO browser
清空列 (CLEAR COLUMN)
CLEAR COLUMN [IF EXISTS] name IN PARTITION partition_name
重置指定分区的列中的所有数据。有关设置分区名称的更多信息,请参见 如何设置分区表达式 部分。
如果指定了 IF EXISTS
子句,则如果列不存在,则查询不会返回错误。
示例
ALTER TABLE visits CLEAR COLUMN browser IN PARTITION tuple()
添加列注释 (COMMENT COLUMN)
COMMENT COLUMN [IF EXISTS] name 'Text comment'
向列添加注释。如果指定了 IF EXISTS
子句,则如果列不存在,则查询不会返回错误。
每个列可以有一个注释。如果列已存在注释,则新注释将覆盖以前的注释。
注释存储在 DESCRIBE TABLE 查询返回的 comment_expression
列中。
示例
ALTER TABLE visits COMMENT COLUMN browser 'This column shows the browser used for accessing the site.'
修改列 (MODIFY COLUMN)
MODIFY COLUMN [IF EXISTS] name [type] [default_expr] [codec] [TTL] [settings] [AFTER name_after | FIRST]
ALTER COLUMN [IF EXISTS] name TYPE [type] [default_expr] [codec] [TTL] [settings] [AFTER name_after | FIRST]
此查询更改 name
列的属性
类型
默认表达式
压缩编解码器
TTL
列级设置
有关修改列压缩编解码器的示例,请参见 列压缩编解码器。
有关修改列 TTL 的示例,请参见 列 TTL。
有关修改列级设置的示例,请参见 列级设置。
如果指定了 IF EXISTS
子句,则如果列不存在,则查询不会返回错误。
更改类型时,值将像应用了 toType 函数一样进行转换。如果仅更改默认表达式,则查询不会执行任何复杂操作,并且几乎会立即完成。
示例
ALTER TABLE visits MODIFY COLUMN browser Array(String)
更改列类型是唯一复杂的操作 - 它会更改包含数据的文件的内容。对于大型表,这可能需要很长时间。
查询还可以使用 FIRST | AFTER
子句更改列的顺序,请参见 添加列 (ADD COLUMN) 说明,但在这种情况下,列类型是必须的。
示例
CREATE TABLE users (
c1 Int16,
c2 String
) ENGINE = MergeTree
ORDER BY c1;
DESCRIBE users;
┌─name─┬─type───┬
│ c1 │ Int16 │
│ c2 │ String │
└──────┴────────┴
ALTER TABLE users MODIFY COLUMN c2 String FIRST;
DESCRIBE users;
┌─name─┬─type───┬
│ c2 │ String │
│ c1 │ Int16 │
└──────┴────────┴
ALTER TABLE users ALTER COLUMN c2 TYPE String AFTER c1;
DESCRIBE users;
┌─name─┬─type───┬
│ c1 │ Int16 │
│ c2 │ String │
└──────┴────────┴
ALTER
查询是原子的。对于 MergeTree 表,它也是无锁的。
更改列的 ALTER
查询会被复制。指令保存在 ZooKeeper 中,然后每个副本都会应用它们。所有 ALTER
查询都按相同的顺序运行。查询将等待在其他副本上完成相应的操作。但是,更改复制表中列的查询可能会被中断,并且所有操作都将异步执行。
移除列属性 (MODIFY COLUMN REMOVE)
删除列的某个属性:DEFAULT
、ALIAS
、MATERIALIZED
、CODEC
、COMMENT
、TTL
、SETTINGS
。
语法
ALTER TABLE table_name MODIFY COLUMN column_name REMOVE property;
示例
删除 TTL
ALTER TABLE table_with_ttl MODIFY COLUMN column_ttl REMOVE TTL;
另请参阅
修改列设置 (MODIFY COLUMN MODIFY SETTING)
修改列设置。
语法
ALTER TABLE table_name MODIFY COLUMN column_name MODIFY SETTING name=value,...;
示例
将列的 max_compress_block_size
修改为 1MB
ALTER TABLE table_name MODIFY COLUMN column_name MODIFY SETTING max_compress_block_size = 1048576;
重置列设置 (MODIFY COLUMN RESET SETTING)
重置列设置,还会从表的 CREATE 查询的列表达式中删除设置声明。
语法
ALTER TABLE table_name MODIFY COLUMN column_name RESET SETTING name,...;
示例
将列设置 max_compress_block_size
重置为其默认值
ALTER TABLE table_name MODIFY COLUMN column_name RESET SETTING max_compress_block_size;
物化列 (MATERIALIZE COLUMN)
物化具有 DEFAULT
或 MATERIALIZED
值表达式的列。使用 ALTER TABLE table_name ADD COLUMN column_name MATERIALIZED
添加物化列时,不会自动填充没有物化值的现有行。在添加或更新 DEFAULT
或 MATERIALIZED
表达式(这只会更新元数据,而不会更改现有数据)之后,可以使用 MATERIALIZE COLUMN
语句重写现有列数据。实现为 mutation。
对于具有新的或更新的 MATERIALIZED
值表达式的列,所有现有行都会被重写。
对于具有新的或更新的 DEFAULT
值表达式的列,其行为取决于 ClickHouse 版本。
- 在 ClickHouse < v24.2 中,所有现有行都会被重写。
- ClickHouse >= v24.2 区分在插入时是否显式指定了具有
DEFAULT
值表达式的列中的行值,即是否从DEFAULT
值表达式计算得出。如果值是显式指定的,ClickHouse 会保持原样。如果值是计算出来的,ClickHouse 会将其更改为新的或更新的MATERIALIZED
值表达式。
语法
ALTER TABLE [db.]table [ON CLUSTER cluster] MATERIALIZE COLUMN col [IN PARTITION partition | IN PARTITION ID 'partition_id'];
- 如果指定了 PARTITION,则列将仅使用指定的分区进行物化。
示例
DROP TABLE IF EXISTS tmp;
SET mutations_sync = 2;
CREATE TABLE tmp (x Int64) ENGINE = MergeTree() ORDER BY tuple() PARTITION BY tuple();
INSERT INTO tmp SELECT * FROM system.numbers LIMIT 5;
ALTER TABLE tmp ADD COLUMN s String MATERIALIZED toString(x);
ALTER TABLE tmp MATERIALIZE COLUMN s;
SELECT groupArray(x), groupArray(s) FROM (select x,s from tmp order by x);
┌─groupArray(x)─┬─groupArray(s)─────────┐
│ [0,1,2,3,4] │ ['0','1','2','3','4'] │
└───────────────┴───────────────────────┘
ALTER TABLE tmp MODIFY COLUMN s String MATERIALIZED toString(round(100/x));
INSERT INTO tmp SELECT * FROM system.numbers LIMIT 5,5;
SELECT groupArray(x), groupArray(s) FROM tmp;
┌─groupArray(x)─────────┬─groupArray(s)──────────────────────────────────┐
│ [0,1,2,3,4,5,6,7,8,9] │ ['0','1','2','3','4','20','17','14','12','11'] │
└───────────────────────┴────────────────────────────────────────────────┘
ALTER TABLE tmp MATERIALIZE COLUMN s;
SELECT groupArray(x), groupArray(s) FROM tmp;
┌─groupArray(x)─────────┬─groupArray(s)─────────────────────────────────────────┐
│ [0,1,2,3,4,5,6,7,8,9] │ ['inf','100','50','33','25','20','17','14','12','11'] │
└───────────────────────┴───────────────────────────────────────────────────────┘
另请参阅
限制
ALTER
查询允许您在嵌套数据结构中创建和删除单独的元素(列),但不能删除整个嵌套数据结构。要添加嵌套数据结构,您可以添加名称类似于 name.nested_name
且类型为 Array(T)
的列。嵌套数据结构等效于多个名称在点号之前具有相同前缀的数组列。
不支持删除主键或采样键中的列(在 ENGINE
表达式中使用的列)。仅当此更改不会导致数据修改时,才能更改包含在主键中的列的类型(例如,允许您向 Enum 添加值或将类型从 DateTime
更改为 UInt32
)。
如果 ALTER
查询不足以进行所需的表更改,您可以创建一个新表,使用 INSERT SELECT 查询将数据复制到其中,然后使用 RENAME 查询切换表并删除旧表。
ALTER
查询会阻止对表的任何读写操作。换句话说,如果在 ALTER
查询执行时正在运行长时间的 SELECT
,则 ALTER
查询将等待其完成。同时,所有对同一表的新查询都将在此 ALTER
运行期间等待。
对于本身不存储数据的表(例如 Merge 和 Distributed),ALTER
仅更改表结构,而不更改下属表的结构。例如,在对 Distributed
表运行 ALTER 时,您还需要对所有远程服务器上的表运行 ALTER
。