赞
踩
前面我们已经介绍过 ClickHouse 是列式存储数据库,并且是按照有序存储、且按照索引粒度建立稀疏索引,所以 ClickHouse 是不擅长做 update/delete 操作的,对于需要经常变化的数据,也不建议使用clickhouse。但是并不是说clickhouse就不能更新数据,clickhouse提供了一种基于alter语句的“突变”(mutations)操作来实现更新/删除操作。在使用mutations操作之前需要注意:
语法格式如下,和标准SQL语法相似:
ALTER TABLE [<database>.]<table> UPDATE <column> = <expression> WHERE <filter_expr>
Examples:
-- 使用字典查找更新
ALTER TABLE website.clicks UPDATE visitor_id = getDict('visitors', 'new_visitor_id', visitor_id)
WHERE visit_date < '2022-01-01';
-- 一次更新多个字段,比多次执行分别更新效率更高
ALTER TABLE website.clicks UPDATE url = substring(url, position(url, '://') + 3), visitor_id = new_visit_id
WHERE visit_date < '2022-01-01';
-- 对于分片表,可以在CLUSTER上执行 mutations,旧版本不支持
ALTER TABLE clicks ON CLUSTER main_cluster UPDATE click_count = click_count / 2
WHERE visitor_id ILIKE '%robot%';
注意:
如果只对某个分区做UPDATE操作,除了在WHERE语句中指定条件外,还可以直接指定分区:
ALTER TABLE [db.]table UPDATE column1 = expr1 [, ...] [IN PARTITION partition_id]
WHERE filter_expr;
-- Example
ALTER TABLE mt UPDATE x = x + 1 IN PARTITION 2 WHERE p = 2;
语法格式如下,和标准SQL语法相似:
ALTER TABLE [<database>.]<table> DELETE WHERE <filter_expr>
Examples:
-- 删除记录
ALTER TABLE website.clicks DELETE WHERE visitor_id in (253, 1002, 4277);
-- 删除分片表数据
ALTER TABLE clicks ON CLUSTER main_cluster WHERE visit_date < '2022-01-02 15:00:00' AND page_id = '573';
注意:
如果只对某个分区做DELETE操作,除了在WHERE语句中指定条件外,还可以直接指定分区:
ALTER TABLE [db.]table DELETE [IN PARTITION partition_id] WHERE filter_expr;
-- Example
ALTER TABLE mt DELETE IN PARTITION 2 WHERE p = 2;
如果删除整个分区数据,应该直接使用drop分区操作,参考第5节。
TRUNCATE TABLE 适用于删除全表数据的情况,而且效率比DELETE更高。语法格式如下,高版本同样支持 ON CLUSTER 子句:
TRUNCATE TABLE [<database].]<table>
需要注意的是在一些低版本clickhouse中,直接对分片表使用TRUNCATE TABLE语句或许不会报错,但是数据并没有被删掉,依然需要对本地表执行操作。
可以删除数据库、表、字典等。语法格式如下:
-- 删除数据库,先删除库中所有表,再删除数据库
DROP DATABASE [IF EXISTS] db [ON CLUSTER cluster];
-- 删除表
DROP [TEMPORARY] TABLE [IF EXISTS] [db.]name [ON CLUSTER cluster];
-- 删除字段
DROP DICTIONARY [IF EXISTS] [db.]name;
-- 删除视图,也可以通过 DROP TABLE 删除
DROP VIEW [IF EXISTS] [db.]name [ON CLUSTER cluster];
语法格式如下,支持添加、删除、重命名字段,清楚列数据,添加注释等,可以通过逗号分隔执行多个列操作:
ALTER TABLE [db].name [ON CLUSTER cluster] ADD|DROP|RENAME|CLEAR|COMMENT|{MODIFY|ALTER}|MATERIALIZE COLUMN ...
语法格式如下:
ALTER TABLE [db].name [ON CLUSTER cluster] ADD COLUMN [IF NOT EXISTS] name [type] [default_expr] [codec] [AFTER name_after | FIRST]
新增列默认是放在最后一列,AFTER 子句可以指定在某个列之后,FIRST 子句表示放在第一列。新增列数据默认都是对应类型的默认值(或者指定的默认值)。
Example:
ALTER TABLE alter_test ADD COLUMN Added1 UInt32 FIRST;
ALTER TABLE alter_test ADD COLUMN Added2 UInt32 AFTER NestedColumn;
语法格式如下:
ALTER TABLE [db].name [ON CLUSTER cluster] DROP COLUMN [IF EXISTS] name
如果列被物化视图引用,则不能被删除。
Example:
ALTER TABLE visits DROP COLUMN browser
语法格式如下:
ALTER TABLE [db].name [ON CLUSTER cluster] RENAME COLUMN [IF EXISTS] name to new_name
不能对 ORDER BY or PRIMARY KEY 字段RENAME,否则报错。
Example:
ALTER TABLE visits RENAME COLUMN webBrowser TO browser
语法格式如下:
ALTER TABLE [db].name [ON CLUSTER cluster] CLEAR COLUMN [IF EXISTS] name IN PARTITION partition_name
清除指定分区上的指定列数据为默认值。
Example:
ALTER TABLE visits CLEAR COLUMN browser IN PARTITION tuple();
ALTER TABLE visits CLEAR COLUMN hour in PARTITION 201902;
语法格式如下:
ALTER TABLE [db].name [ON CLUSTER cluster] COMMENT COLUMN [IF EXISTS] name 'Text comment'
每一列可以有一个注释。如果该列已有注释,则新注释将覆盖以前的注释。表字段注释可以通过 DESCRIBE TABLE 语句查询。
Example:
ALTER TABLE visits COMMENT COLUMN browser 'The table shows the browser used for accessing the site.'
语法格式如下:
ALTER TABLE [db].name [ON CLUSTER cluster] MODIFY COLUMN [IF EXISTS] name [type] [default_expr] [codec] [TTL] [AFTER name_after | FIRST];
ALTER TABLE [db].name [ON CLUSTER cluster] ALTER COLUMN [IF EXISTS] name TYPE [type] [default_expr] [codec] [TTL] [AFTER name_after | FIRST];
修改列语句支持MODIFY / ALTER关键词,可以修改列类型、列顺序、TTL、压缩算法、默认值等。在更改类型时,将对值进行转换,就像对它们应用toType函数一样,需要花费较多时间。如果只更改默认表达式,则查询不会执行任何复杂的操作,而且几乎可以立即完成。
Example:
-- 更改字段类型
ALTER TABLE visits MODIFY COLUMN browser Array(String)
语法格式如下:
ALTER TABLE table_name MODIFY column_name REMOVE property;
可删除列默认值、压缩算法、注释、TTL等。
Example:
-- 删除TTL
ALTER TABLE table_with_ttl MODIFY COLUMN column_ttl REMOVE TTL;
支持卸载、删除、加载、拷贝、移动、备份等操作。
语法格式如下:
ALTER TABLE table_name DETACH PARTITION|PART partition_expr
卸载分区的意思是把分区数据移动到 detached 目录,相当于数据从表中被删除,但是没有完全删除,还可以通过 ATTACH 语句加载分区,恢复数据,类似于我们电脑的回收站机制。
Example:
ALTER TABLE mt DETACH PARTITION '2020-11-21';
ALTER TABLE mt DETACH PART 'all_2_2_0';
对于副本表,DETACH 语句会被同步到所有副本节点上执行,但是 DETACH 语句本身只能在leader节点上执行,可以通过 system.replicas 表查询leader副本节点,也可以对所有副本执行 DETACH 语句,非leader副本会抛出异常。
语法格式如下:
ALTER TABLE table_name ATTACH PARTITION|PART partition_expr
从 detached 目录中加载分区或部分数据,可以是已卸载的分区数据或者是复合格式的数据文件。
Examples:
ALTER TABLE visits ATTACH PARTITION 201901;
ALTER TABLE visits ATTACH PART 201901_2_2_0;
对于副本表,该操作同样会同步到所有副本执行,如果当前副本 detached 目录没有复合条件的数据,而其他副本节点有,则当前副本会从其他副本下载数据,所以如果是外部数据,放置在任何一个副本节点上即可。
语法格式如下:
ALTER TABLE table_name DROP PARTITION|PART partition_expr
删除分区数据并不会立即被删除,首先把分区标记为 inactive(非活跃),然后大约在10分钟内完全删除数据。在副本表上执行时,会删除所有副本分区。
Example:
ALTER TABLE mt DROP PARTITION '2020-11-21';
ALTER TABLE mt DROP PART 'all_4_4_0';
语法格式如下:
ALTER TABLE table_name DROP DETACHED PARTITION|PART partition_expr
语法格式如下:
ALTER TABLE table2 ATTACH PARTITION partition_expr FROM table1
从表table1中复制分区到表table2,两个表必须具有相同的表结构和分区键。
语法格式如下:
ALTER TABLE table2 REPLACE PARTITION partition_expr FROM table1
从表table1中复制分区到表table2,并替换table2中已存在的同名分区,两个表必须具有相同的表结构和分区键。
移动分区有两种情况:从一个表移动到另一个表、从一个表移动到磁盘。
(1) 从一个表移动到另一个表
语法格式如下:
ALTER TABLE table_source MOVE PARTITION partition_expr TO TABLE table_dest
从表table_source中移动分区到表table_dest,table_source中的分区会被删除,两个表必须具有相同的表结构、分区键、家族表引擎(区分副本和非副本表)以及相同的存储策略。
(2) 从一个表移动到磁盘
ALTER TABLE table_name MOVE PARTITION|PART partition_expr TO DISK|VOLUME 'disk_name'
该操作不会同步到所有副本节点上,因为不同的副本可以有不同的存储策略。
语法格式如下:
ALTER TABLE table_name FREEZE [PARTITION partition_expr] [WITH NAME 'backup_name']
此查询创建指定分区的本地备份。如果省略PARTITION子句,查询将立即创建所有分区的备份。该查询不会自动复制到所有副本节点上,只会对当前节点做备份,且只备份数据,不备份元数据信息,如果需要备份元数据,需要拷贝 /var/lib/clickhouse/metadata/database/table.sql 文件。
语法格式如下:
ALTER TABLE 'table_name' UNFREEZE [PARTITION 'part_expr'] WITH NAME 'backup_name'
从磁盘中移除指定名称的备份分区。如果省略PARTITION子句,查询将立即删除所有分区的备份。
语法格式如下:
ALTER TABLE table_name CLEAR INDEX index_name IN PARTITION partition_expr
几乎所有的分区操作都需要指定 partition_expr(分区表达式),但是我们在建表的时候分区定义可能是五花八门,可以是数值型字段、时间类型字段,或者字段的一部分等等,怎么确定分区表达式呢?
同样,OPTIMIZE 语句也支持指定分区:
OPTIMIZE TABLE table_not_partitioned PARTITION tuple() FINAL;
在前面介绍MergeTree表原理和建表语句的文章中,我们介绍了建表语句中的 SETTINGS 选项,可以指定一系列参数。同样,这些参数也是可以更改的(只适用于MergeTree表)。语法格式如下,可以同时修改多个设置参数:
ALTER TABLE [db].name [ON CLUSTER cluster] MODIFY|RESET SETTING ...
Example:
CREATE TABLE example_table (id UInt32, data String) ENGINE=MergeTree() ORDER BY id;
ALTER TABLE example_table MODIFY SETTING max_part_loading_threads=8, max_parts_in_total=50000;
恢复SETTING项到默认值:
CREATE TABLE example_table (id UInt32, data String) ENGINE=MergeTree() ORDER BY id
SETTINGS max_part_loading_threads=8;
ALTER TABLE example_table RESET SETTING max_part_loading_threads;
clickhouse 除了主键中的稀疏索引以外,还支持二级索引(跳数索引),在前面介绍二级索引的文章中,我们介绍了二级索引的种类、原理,以及在建表语句中怎么创建二级索引。除了在建表语句中定义二级索引外,我们还可以在后期添加、删除二级索引。
语法格式如下:
-- 添加二级索引
ALTER TABLE [db].name ADD INDEX name expression TYPE type GRANULARITY value [FIRST|AFTER name];
-- 删除索引
ALTER TABLE [db].name DROP INDEX name;
-- 重建索引,一般用于新增索引对历史数据生效
ALTER TABLE [db.]table MATERIALIZE INDEX name [IN PARTITION partition_name];
Example:
-- 对表skip_table的my_value列建立名为vix的set二级索引
ALTER TABLE skip_table ADD INDEX vix my_value TYPE set(100) GRANULARITY 2;
需要注意新建立的二级索引只对新增数据有效,所以是一个轻量级操作,如果想要对历史数据也有效,需要执行:
ALTER TABLE skip_table MATERIALIZE INDEX vix;
该操作需要对历史数据重建索引,所以是一个 mutation 操作。
二级索引操作语句会自动同步到所有副本节点上。
建表指定约束:
CREATE TABLE [IF NOT EXISTS] [db.]table_name [ON CLUSTER cluster]
(
name1 [type1] [DEFAULT|MATERIALIZED|ALIAS expr1] [compression_codec] [TTL expr1],
...
CONSTRAINT constraint_name_1 CHECK boolean_expr_1,
...
) ENGINE = engine
添加、删除约束:
ALTER TABLE [db].name ADD CONSTRAINT constraint_name CHECK expression;
ALTER TABLE [db].name DROP CONSTRAINT constraint_name;
约束操作语句对所有副本有效。添加大量的约束可能会对大型INSERT操作的性能产生影响。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。