三 clickhouse基础入门
基本语法演示
-- show databases ; -- create database if not exists test1 ; -- use test1 ; -- select currentDatabase() ; -- drop database test1 ;
1 数据类型
注意在CK中关键字严格区分大小写
create table tb_test1( id Int8 , name String )engine=Memory; ┌─name─┬─type───┬─default_type─┬─default_expression─┬─comment─┬─codec_expression─┬─ttl_expression─┐ │ id │ Int8 │ │ │ │ │ │ │ name │ String │ │ │ │ │ │ └──────┴────────┴──────────────┴────────────────────┴─────────┴──────────────────┴────────────────┘
1.1 数值类型
1) IntX和UIntX
*ClickHouse支持无符号的整数,使用前缀U表示*
create table test_int( id Int8 , age UInt8 , cdId Int32 )engine=Memory ;
注意: 和我以前的认知是一样的,这种数据类型在数据特别精准的情况下可能出现数据精度问题!
Select 8.0/0 -->inf 正无穷
Select -8.0/0 -->inf 负无穷
Select 0/0 -->nan 非数字
如果要求更高精度的数值运算,则需要使用定点数。ClickHouse提 供了Decimal32、Decimal64和Decimal128三种精度的定点数。可以通过 两种形式声明定点:简写方式有Decimal32(S)、Decimal64(S)、
Decimal128(S)三种,原生方式为Decimal(P,S),其中:
·P代表精度,决定总位数(整数部分+小数部分),取值范围是1 ~38;·S代表规模,决定小数位数,取值范围是0~P
在使用两个不同精度的定点数进行四则运算的时候,它们的小数点 位数S会发生变化。
在进行加法运算时,S取最大值。例如下面的查询,toDecimal64(2,4)与toDecimal32(2,2)相加后S=4:
在进行减法运算时,S取最大值。例如下面的查询,toDecimal64(2,4)与toDecimal32(2,2)相减后S=4:
在进行乘法运算时,S取最和。例如下面的查询,toDecimal64(2,4)与toDecimal32(2,2)相乘后S=4+2:
在进行除法运算时,S取最大值。例如下面的查询,toDecimal64(2,4)与toDecimal32(2,2)相除后S=4:但是要保证被除数的S大于除数的S,否则会报错
1.2 字符串类型
1) String
字符串由String定义,长度不限。因此在使用String的时候无须声明大小。它完全代替了传统意义上数据库的Varchar、Text、Clob和Blob等字符类型。String类型不限定字符集,因为它根本就没有这个概念,所以可以将任意编码的字符串存入其中。但是为了程序的规范性和可维护性,在同一套程序中应该遵循使用统一的编码,例如“统一保持UTF-8编码”就是一种很好的约定。所以在对数据操作的时候我们不在需要区关注编码和乱码问题!
2) FixedString
FixedString类型和传统意义上的Char类型有些类似,对于一些字符有明确长度的场合,可以使用固定长度的字符串。定长字符串通过FixedString(N)声明,其中N表示字符串长度。但与Char不同的是,FixedString使用null字节填充末尾字符,而Char通常使用空格填充。比如在下面的例子中,字符串‘abc’虽然只有3位,但长度却是5,因为末尾有2位空字符填充 !
create table test_str( name String , job FixedString(4) -- 最长4个字符 )engine=Memory ;
3) UUID
CREATE TABLE test_uuid ( `uid` UUID, `name` String ) ENGINE = Memory ; DESCRIBE TABLE test_uuid ┌─name─┬─type───┬ │ uid │ UUID │ │ name │ String │ └──────┴────────┴ insert into test_uuid select generateUUIDv4() , 'zss' ; select * from test_uuid ; ┌──────────────────────────────────uid─┬─name─┐ │ 47e39e22-d2d6-46fd-8014-7cd3321f4c7b │ zss │ └──────────────────────────────────────┴──────┘ -------------------------UUID类型的字段默认补位0----------------------------- insert into test_uuid (name) values('hangge') ; ┌──────────────────────────────────uid─┬─name─┐ │ 47e39e22-d2d6-46fd-8014-7cd3321f4c7b │ zss │ └──────────────────────────────────────┴──────┘ ┌──────────────────────────────────uid─┬─name───┐ │ 00000000-0000-0000-0000-000000000000 │ hangge │ └──────────────────────────────────────┴────────┘
1) Date
Date类型不包含具体的时间信息,只精确到天,支持字符串形式写入:
CREATE TABLE test_date ( `id` int, `ct` Date ) ENGINE = Memory ; DESCRIBE TABLE test_date ; ┌─name─┬─type──┬ │ id │ Int32 │ │ ct │ Date │ └──────┴───────┴ insert into test_date vlaues(1,'2021-09-11'),(2,now()) ; select id , ct from test_date ; ┌─id─┬─────────ct─┐ │ 1 │ 2021-09-11 │ │ 2 │ 2021-05-17 │ └────┴────────────┘
DateTime类型包含时、分、秒信息,精确到秒,支持字符串形式写入:
create table testDataTime(ctime DateTime) engine=Memory ; insert into testDataTime values('2021-12-27 01:11:12'),(now()) ; select * from testDataTime ;
DateTime64可以记录亚秒,它在DateTime之上增加了精度的设置
-- 建表 CREATE TABLE test_date_time64 ( `ctime` DateTime64 ) ENGINE = Memory ; -- 建表 CREATE TABLE test_date_time64_2 ( `ctime` DateTime64(2) ) ENGINE = Memory ; -- 分别插入数据 insert into test_date_time64 values('2021-11-11 11:11:11'),(now()) ; insert into test_date_time64_2 values('2021-11-11 11:11:11'),(now()) ; -- 查询数据 SELECT * FROM test_date_time64; ┌───────────────────ctime─┐ │ 2021-11-11 11:11:11.000 │ │ 2021-05-17 10:40:51.000 │ └─────────────────────────┘ SELECT *, toTypeName(ctime) FROM test_date_time64 ┌───────────────────ctime─┬─toTypeName(ctime)─┐ │ 2021-11-11 11:11:11.000 │ DateTime64(3) │ │ 2021-05-17 10:40:51.000 │ DateTime64(3) │ ------------------------------------------------ SELECT *, toTypeName(ctime) FROM test_date_time64_2 ┌──────────────────ctime─┬─toTypeName(ctime)─┐ │ 2021-11-11 11:11:11.00 │ DateTime64(2) │ │ 2021-05-17 10:41:26.00 │ DateTime64(2) │ └────────────────────────┴───────────────────┘
1.4 复杂类型
1) Enum
create table test_enum(id Int8 , color Enum('red'=1 , 'green'=2 , 'blue'=3)) engine=Memory ; insert into test_enum values(1,'red'),(1,'red'),(2,'green'); 也可以使用这种方式进行插入数据: insert into test_enum values(3,3) ;
在定义枚举集合的时候,有几点需要注意。首先,Key和Value是不允许重复的,要保证唯一性。其次,Key和Value的值都不能为Null,但Key允许是空字符串。在写入枚举数据的时候,只会用到Key字符串部分,
注意: 其实我们可以使用字符串来替代Enum类型来存储数据,那么为什么是要使用枚举类型呢?这是出于性能的考虑。因为虽然枚举定义中的Key属于String类型,但是在后续对枚举的所有操作中(包括排序、分组、去重、过滤等),会使用Int类型的Value值 ,提高处理数据的效率!
-
限制枚举类型字段的值
-
底层存储的是对应的Int类型的数据
-
可以使用String
2) Array(T)
CK支持数组这种复合数据类型 , 并且数据在操作在今后的数据分析中起到非常便利的效果!数组的定义方式有两种 : array(T) [e1,e2...] , 我们在这里要求数组中的数据类型是一致的!
数组的定义 [1,2,3,4,5] array('a' , 'b' , 'c') [1,2,3,'hello'] -- 错误 create table test_array( id Int8 , hobby Array(String) )engine=Memory ; insert into test_array values(1,['eat','drink','la']),(2,array('sleep','palyg','sql')); ┌─id─┬─hobby───────────────────┐ │ 1 │ ['eat','drink','la'] │ │ 2 │ ['sleep','palyg','sql'] │ └────┴─────────────────────────┘ select id , hobby , toTypeName(hobby) from test_array ; ┌─id─┬─hobby───────────────────┬─toTypeName(hobby)─┐ │ 1 │ ['eat','drink','la'] │ Array(String) │ │ 2 │ ['sleep','palyg','sql'] │ Array(String) │ └────┴─────────────────────────┴───────────────────┘ select id , hobby[2] , toTypeName(hobby) from test_array ; -- 数组的取值 [index] 1-based
3) Tuple
select tuple(1,'asb',12.23) as x , toTypeName(x) ; ┌─x───────────────┬─toTypeName(tuple(1, 'asb', 12.23))─┐ │ (1,'asb',12.23) │ Tuple(UInt8, String, Float64) │ └─────────────────┴────────────────────────────────────┘ ---简写形式 SELECT (1, 'asb', 12.23) AS x, toTypeName(x) ┌─x───────────────┬─toTypeName(tuple(1, 'asb', 12.23))─┐ │ (1,'asb',12.23) │ Tuple(UInt8, String, Float64) │ └─────────────────┴────────────────────────────────────┘ 注意:建表的时候使用元组的需要制定元组的数据类型 CREATE TABLE test_tuple ( c1 Tuple(UInt8, String, Float64) ) ENGINE = Memory;
-
-
tuple(1,2,3,'abc')
-
4) Nested
Nested是一种嵌套表结构。一张数据表,可以定义任意多个嵌套类型字段,但每个字段的嵌套层级只支持一级,即嵌套表内不能继续使用嵌套类型。对于简单场景的层级关系或关联关系,使用嵌套类型也是一种不错的选择。
create table test_nested( uid Int8 , name String , props Nested( pid Int8, pnames String , pvalues String ) )engine = Memory ; desc test_nested ; ┌─name──────────┬─type──────────┬ │ uid │ Int8 │ │ name │ String │ │ props.pid │ Array(Int8) │ │ props.pnames │ Array(String) │ │ props.pvalues │ Array(String) │ └───────────────┴───────────────┴
嵌套类型本质是一种多维数组的结构。嵌套表中的每个字段都是一个数组,并且行与行之间数组的长度无须对齐。需要注意的是,在同一行数据内每个数组字段的长度必须相等。
insert into test_nested values(1,'hadoop',[1,2,3],['p1','p2','p3'],['v1','v2','v3']); -- 行和行之间的属性的个数可以不一致 ,但是当前行的Nested类型中的数组个数必须一致 insert into test_nested values(2,'spark',[1,2],['p1','p2'],['v1','v2']); SELECT * FROM test_nested ┌─uid─┬─name───┬─props.pid─┬─props.pnames─────┬─props.pvalues────┐ │ 1 │ hadoop │ [1,2,3] │ ['p1','p2','p3'] │ ['v1','v2','v3'] │ └─────┴────────┴───────────┴──────────────────┴──────────────────┘ ┌─uid─┬─name──┬─props.pid─┬─props.pnames─┬─props.pvalues─┐ │ 2 │ spark │ [1,2] │ ['p1','p2'] │ ['v1','v2'] │ └─────┴───────┴───────────┴──────────────┴───────────────┘ SELECT uid, name, props.pid, props.pnames[1] FROM test_nested; ┌─uid─┬─name───┬─props.pid─┬─arrayElement(props.pnames, 1)─┐ │ 1 │ hadoop │ [1,2,3] │ p1 │ └─────┴────────┴───────────┴───────────────────────────────┘ ┌─uid─┬─name──┬─props.pid─┬─arrayElement(props.pnames, 1)─┐ │ 2 │ spark │ [1,2] │ p1 │ └─────┴───────┴───────────┴───────────────────────────────┘
create table test_nested( id Int8 , name String , scores Nested( seq UInt8 , sx Float64 , yy Float64 , yw Float64 ) )engine = Memory ; insert into test_nested values (1,'wbb',[1,2,3],[11,12,13],[14,14,11],[77,79,10]); insert into test_nested values (2,'taoge',[1,2],[99,10],[14,40],[77,11]); -- 注意 每行中的数组的个数一致 行和行之间可以不一直被 ┌─id─┬─name─┬─scores.seq─┬─scores.sx──┬─scores.yy──┬─scores.yw──┐ │ 1 │ wbb │ [1,2,3] │ [11,12,13] │ [14,14,11] │ [77,79,10] │ └────┴──────┴────────────┴────────────┴────────────┴────────────┘ ┌─id─┬─name──┬─scores.seq─┬─scores.sx─┬─scores.yy─┬─scores.yw─┐ │ 2 │ taoge │ [1,2] │ [99,10] │ [14,40] │ [77,11] │ └────┴───────┴────────────┴───────────┴───────────┴───────────┘ SELECT name, scores.sx FROM test_nested; ┌─name─┬─scores.sx──┐ │ wbb │ [11,12,13] │ └──────┴────────────┘ ┌─name──┬─scores.sx─┐ │ taoge │ [99,10] │ └───────┴───────────┘
https://repo.yandex.ru/clickhouse/rpm/testing/x86_64/ 下载新版本的CK安装包
SET allow_experimental_geo_types = 1; CREATE TABLE geo_point (p Point) ENGINE = Memory(); INSERT INTO geo_point VALUES((10, 10)); SELECT p, toTypeName(p) FROM geo_point; ┌─p───────┬─toTypeName(p)─┐ │ (10,10) │ Point │ └─────────┴───────────────┘
SET allow_experimental_geo_types = 1; CREATE TABLE geo_ring (r Ring) ENGINE = Memory(); INSERT INTO geo_ring VALUES([(0, 0), (10, 0), (10, 10), (0, 10)]); SELECT r, toTypeName(r) FROM geo_ring; ┌─r─────────────────────────────┬─toTypeName(r)─┐ │ [(0,0),(10,0),(10,10),(0,10)] │ Ring │ └───────────────────────────────┴───────────────┘
SET allow_experimental_geo_types = 1; CREATE TABLE geo_polygon (pg Polygon) ENGINE = Memory(); INSERT INTO geo_polygon VALUES([[(20, 20), (50, 20), (50, 50), (20, 50)], [(30, 30), (50, 50), (50, 30)]]); SELECT pg, toTypeName(pg) FROM geo_polygon;
SET allow_experimental_geo_types = 1; CREATE TABLE geo_multipolygon (mpg MultiPolygon) ENGINE = Memory(); INSERT INTO geo_multipolygon VALUES([[[(0, 0), (10, 0), (10, 10), (0, 10)]], [[(20, 20), (50, 20), (50, 50), (20, 50)],[(30, 30), (50, 50), (50, 30)]]]); SELECT mpg, toTypeName(mpg) FROM geo_multipolygon;
7)IPV4
域名类型分为IPv4和IPv6两类,本质上它们是对整型和字符串的进一步封装。IPv4类型是基于UInt32封装的
(1)出于便捷性的考量,例如IPv4类型支持格式检查,格式错误的IP数据是无法被写入的,例如:
INSERT INTO IP4_TEST VALUES ('www.51doit.com','192.0.0')
Code: 441. DB::Exception: Invalid IPv4 value.
(2)出于性能的考量,同样以IPv4为例,IPv4使用UInt32存储,相比String更加紧凑,占用的空间更小,查询性能更快。IPv6类型是基于FixedString(16)封装的,它的使用方法与IPv4别无二致, 在使用Domain类型的时候还有一点需要注意,虽然它从表象上看起来与String一样,但Domain类型并不是字符串,所以它不支持隐式的自动类型转换。如果需要返回IP的字符串形式,则需要显式调用 IPv4NumToString或IPv6NumToString函数进行转换。
create table test_domain( id Int8 , ip IPv4 )engine=Memory ; insert into test_domain values(1,'192.168.133.2') ; insert into test_domain values(1,'192.168.133') ; 在插入数据的会进行数据的检查所以这行数据会报错 -- Exception on client: -- Code: 441. DB::Exception: Invalid IPv4 value. -- Connecting to database doit1 at localhost:9000 as user default. -- Connected to ClickHouse server version 20.8.3 revision 54438.
8) Boolean和Nullable
ck中没有Boolean类型 ,使用1和0来代表true和false
Nullable 某种数据类型允许为null , 或者是没有给值的情况下模式是NULL
create table test_null( id Int8 , age Int8 )engine = Memory ; create table test_null2( id Int8 , age Nullable(Int8) )engine = Memory ;
2.1 DDL基础
-
建表
目前只有MergeTree、Merge和Distributed这三类表引擎支持 ALTER查询,所以在进行alter操作的时候注意表的引擎!
注意在建表的时候一般要求指定表的引擎
CREATE TABLE tb_test1 ( `id` Int8, `name` String ) ENGINE = Memory() ; -- 只有 MergeTree支持表结构的修改 -- MergeTree一定指定主键和排序字段 order by 代表两个含义 CREATE TABLE test_alter1 ( `id` Int8, `name` String ) ENGINE = MergeTree() order by id ; -- 查看建表语句 查看引擎类型参数值 show create table test_alter1 ; ----------------------------------- CREATE TABLE doit23.test_alter1 ( `id` Int8, `name` String ) ENGINE = MergeTree() ORDER BY id SETTINGS index_granularity = 8192;
-- 查看表结构 desc tb_test1 ; ┌─name─┬─type───┬ │ id │ Int8 │ │ name │ String │ └──────┴────────┴ -- 添加字段 alter table tb_test1 add column age UInt8 ;-- 报错 , 因为修改的表引擎是内存引擎,不支持表结构的修改 -- 创建一张MergeTree引擎的表 CREATE TABLE tb_test2 ( `id` Int8, `name` String ) ENGINE = MergeTree() ORDER BY id ; ┌─name─┬─type───┬ │ id │ Int8 │ │ name │ String │ └──────┴────────┴ -- 添加字段 alter table tb_test2 add column age UInt8 ; ┌─name─┬─type───┬ │ id │ Int8 │ │ name │ String │ │ age │ UInt8 │ └──────┴────────┴ alter table tb_test2 add column gender String after name ; ┌─name───┬─type───┬ │ id │ Int8 │ │ name │ String │ │ gender │ String │ │ age │ UInt8 │ └────────┴────────┴ -- 删除字段 alter table tb_test2 drop column age ; -- 修改字段的数据类型 alter table tb_test2 modify column gender UInt8 default 0 ; ┌─name───┬─type───┬─default_type─┬─default_expression─┬ │ id │ Int8 │ │ │ │ name │ String │ │ │ │ gender │ UInt8 │ DEFAULT │ 0 │ └────────┴────────┴──────────────┴────────────────────┴ -- 作为一个优秀的程序员,表的字段使用注释一种良好的习惯, 所以建议大家在操作的时候使用注释来描述字段的意义 -- 修改 / 添加字段的注释 内部使用的编码默认是UTF8 alter table tb_test2 comment column name '用户名' ; ┌─name───┬─type───┬─default_type─┬─default_expression─┬─comment─┬ │ id │ Int8 │ │ │ │ │ name │ String │ │ │ 用户名 │ │ gender │ UInt8 │ DEFAULT │ 0 │ │ └────────┴────────┴──────────────┴────────────────────┴─────────┴
-
移动表
在Linux系统中,mv命令的本意是将一个文件从原始位置A移动到目标位置B,但是如果位 置A与位置B相同,则可以变相实现重命名的作用。ClickHouse的RENAME查询就与之有着异曲同工之妙,RENAME语句的完整语法如下所示:
-- 修改表名 rename table tb_test1 to t1 ; -- 修改多张表名 rename table tb_test2 to t2 , t1 to tt1 ; -- 移动表到另一数据库中 rename table t2 to test1.t ; -- 查看数据库下的所有的表 show tables ; show tables from db_name ;
-
设置表属性
-- 设置列的默认值 create table tb_test3( id Int8 , name String comment '用户名' , role String comment '角色' default 'VIP' )engine = Log ; ┌─name─┬─type───┬─default_type─┬─default_expression─┬ │ id │ Int8 │ │ │ │ name │ String │ │ │ │ role │ String │ DEFAULT │ 'VIP' │ └──────┴────────┴──────────────┴────────────────────┴ insert into tb_test3 (id , name) values(1,'HANGGE') ; SELECT * FROM tb_test3 ; ┌─id─┬─name───┬─role─┐ │ 1 │ HANGGE │ VIP │ └────┴────────┴──────┘
2.2 DML基础
1) 插入数据
INSERT语句支持三种语法范式,三种范式各有不同,可以根据写入的需求灵活运用。
第一种方式
使用VALUES格式的常规语法
INSERT INTO [db.]table [(c1, c2, c3…)] VALUES (v11, v12, v13…), (v21, v22, v23…), ...
其中,c1、c2、c3是列字段声明,可省略。VALUES后紧跟的是由元组组成的待写入数据,通过下标位 与列字段声明一一对应。数据支持批量声明写入,多行数据之间使用逗号分隔
第二种方式
静态数据: cat user.txt 1,zss,23,BJ,M 2,lss,33,NJ,M 3,ww,21,SH,F create table test_load1( id UInt8 , name String , age UInt8 , city String , gender String )engine=Log ; -- 将数据导入到表中 cat user.txt | clickhouse-client -q 'insert into default.test_load1 format CSV' clickhouse-client -q 'insert into default.test_load1 format CSV' < user.txt 上面的两种方式都可以将数据导入到表中 -- 我们还可以执行数据行属性的分割符 clickhouse-client --format_csv_delimiter=',' -q 'insert into default.test_load1 format CSV' < user.txt
第三种方式
INSERT INTO [db.]table [(c1, c2, c3…)] SELECT ...
虽然VALUES和SELECT子句的形式都支持声明表达式或函数,但是表达式和函数会带来额外的性能开销,从而导致写入性能的下降。所以如果追求极致的写入性能,就应该尽可能避免使用它们。
create table log3 as log2 ; Insert into log3 select * from log2 ;
ClickHouse内部所有的数据操作都是面向Block数据块的,所以INSERT查询最终会将数据转换为Block数据块。也正因如此,INSERT语句在单个数据块的写入过程中是具有原子性的。在默认的情况下,每个数据块最多可以写入1048576行数据(由max_insert_block_size参数控制)。也就是说,如果一条INSERT语句写入的数据少于max_insert_block_size行,那么这批数据的写入是具有原子性的,即要么全部成功,要么全部失败。需要注意的是,只有在ClickHouse服务端处理数据的时候才具有这种原子写入的特性,例如使用JDBC或者HTTP接口时。因为max_insert_block_size参数在使用CLI命令行或 者INSERT SELECT子句写入时是不生效的。
2) 更新删除数据
ClickHouse提供了DELETE和UPDATE的能力,这类操作被称为Mutation查询,它可以看作ALTER语句的变种。虽然Mutation能最终实现修改和删除,但不能完全以通常意义上的UPDATE和DELETE来理解,我们必须清醒地认识到它的不同:首先,Mutation语句是一种“很重”的操作,更适用于批量数据的修改和删除;其次,它不支持事务,一旦语句被提交执行,就会立刻对现有数据产生影响,无法回滚;最后, Mutation语句的执行是一个异步的后台过程,语句被提交之后就会立即返回。所以这并不代表具体逻辑已经执行完毕,它的具体执行进度需要通过system.mutations系统表查询。注意数据的修改和删除操作是使用用MergeTree家族引擎:
只有MergeTree引擎的数据才能修改
删除分区数据
-- 创建表 create table test_muta( id UInt8 , name String , city String )engine=MergeTree() partition by city order by id ; -- 导入数据 clickhouse-client -q 'insert into test_muta format CSV' < data.csv -- 删除分区数据 alter table test_muta drop partition 'SH' ;
条件删除数据
alter table test_muta delete where id=3 ; -- 一定加条件
条件更新数据
ALTER TABLE [db_name.]table_name UPDATE column1 = expr1 [, ...] WHERE filter_expr ALTER TABLE test_ud UPDATE name = 'my', job = 'teacher' WHERE id = '2' ; alter table test_muta update name='李思思' where id=3 ;
但是注意的时候一定指定where条否则会报错,这种语法的where条件也可以使用子查询 ;
2.3 分区表操作
目前只有MergeTree系列 的表引擎支持数据分区,分区的基本概念和意义和hive中的意义一样,这里不过多赘述!
区内排序 , 合并 ,去重
create table test_partition1( id String , ctime DateTime )engine=MergeTree() partition by toYYYYMM(ctime) order by (id) ; -- 查看建表语句 │ CREATE TABLE default.test_partition1 ( `id` String, `ctime` DateTime ) ENGINE = MergeTree() PARTITION BY toYYYYMM(ctime) ORDER BY id SETTINGS index_granularity = 8192 │ -- 插入数据 insert into test_partition1 values(1,now()) ,(2,'2021-06-11 11:12:13') ; -- 查看数据 SELECT * FROM test_partition1 ; ┌─id─┬───────────────ctime─┐ │ 2 │ 2021-06-11 11:12:13 │ └────┴─────────────────────┘ ┌─id─┬───────────────ctime─┐ │ 1 │ 2021-05-19 13:38:29 │ └────┴─────────────────────┘ -- 查看表中的分区 ClickHouse内置了许多system系统表,用于查询自身的状态信息。 其中parts系统表专门用于查询数据表的分区信息。 SELECT name, table, partition FROM system.parts WHERE table = 'test_partition1' ; ┌─name─────────┬─table───────────┬─partition─┐ │ 202105_1_1_0 │ test_partition1 │ 202105 │ │ 202106_2_2_0 │ test_partition1 │ 202106 │ └──────────────┴─────────────────┴───────────┘ insert into test_partition1 values(1,now()) ,(2,'2021-06-12 11:12:13') ; ┌─name─────────┬─table───────────┬─partition─┐ │ 202105_1_1_0 │ test_partition1 │ 202105 │ │ 202105_3_3_0 │ test_partition1 │ 202105 │ │ 202106_2_2_0 │ test_partition1 │ 202106 │ │ 202106_4_4_0 │ test_partition1 │ 202106 │ └──────────────┴─────────────────┴───────────┘ -- 删除分区 alter table test_partition1 drop partition '202105' ; 删除分区以后 , 分区中的所有的数据全部删除 SELECT name, table, partition FROM system.parts WHERE table = 'test_partition1' ┌─name─────────┬─table───────────┬─partition─┐ │ 202106_2_2_0 │ test_partition1 │ 202106 │ │ 202106_4_4_0 │ test_partition1 │ 202106 │ └──────────────┴─────────────────┴───────────┘ SELECT * FROM test_partition1 ┌─id─┬───────────────ctime─┐ │ 2 │ 2021-06-12 11:12:13 │ └────┴─────────────────────┘ ┌─id─┬───────────────ctime─┐ │ 2 │ 2021-06-11 11:12:13 │ └────┴─────────────────────┘ -- 复制分区 clickHouse支持将A表的分区数据复制到B表,这项特性可以用于快速数据写入、多表间数据同步和备份等场景,它的完整语法如下: ALTER TABLE B REPLACE PARTITION partition_expr FROM A 不过需要注意的是,并不是任意数据表之间都能够相互复制,它们还需要满足两个前提 条件: ·两张表需要拥有相同的分区键 ·它们的表结构完全相同。 create table test_partition2 as test_partition1 ; show create table test_partition2 ; -- 查看表2的建表语句 │ CREATE TABLE default.test_partition2 ( `id` String, `ctime` DateTime ) ENGINE = MergeTree() PARTITION BY toYYYYMM(ctime) ORDER BY id SETTINGS index_granularity = 8192 │ -- 两张表的结构完全一致 -- 复制一张表的分区到另一张表中 SELECT * FROM test_partition2 ┌─id─┬───────────────ctime─┐ │ 2 │ 2021-06-12 11:12:13 │ └────┴─────────────────────┘ ┌─id─┬───────────────ctime─┐ │ 2 │ 2021-06-11 11:12:13 │ └────┴─────────────────────┘ ┌─id─┬───────────────ctime─┐ │ 2 │ 2021-06-21 11:12:13 │ └────┴─────────────────────┘ ---------------------------- alter table test_partition2 replace partition '202106' from test_partition1 SELECT name, table, partition FROM system.parts WHERE table = 'test_partition2' ┌─name─────────┬─table───────────┬─partition─┐ │ 202106_2_2_0 │ test_partition2 │ 202106 │ │ 202106_3_3_0 │ test_partition2 │ 202106 │ │ 202106_4_4_0 │ test_partition2 │ 202106 │ └──────────────┴─────────────────┴───────────┘ -- 重置分区数据 如果数据表某一列的数据有误,需要将其重置为初始值,如果设置了默认值那么就是默认值数据,如果没有设置默认值,系统会给出默认的初始值,此时可以使用下面的语句实现: ALTER TABLE tb_name CLEAR COLUMN column_name IN PARTITION partition_expr ; 注意: 不能重置主键和分区字段 示例: alter table test_rep clear column name in partition '202105' ; -- 卸载分区 表分区可以通过DETACH语句卸载,分区被卸载后,它的物理数据并没有删除,而是被转移到了当前数据表目录的detached子目录下。而装载分区则是反向操作,它能够将detached子目录下的某个分区重新装载回去。卸载与装载这一对伴生的操作,常用于分区数据的迁移和备份场景 ┌─id─┬─name─┬───────────────ctime─┐ │ 1 │ │ 2021-05-19 13:59:49 │ │ 2 │ │ 2021-05-19 13:59:49 │ └────┴──────┴─────────────────────┘ ┌─id─┬─name─┬───────────────ctime─┐ │ 3 │ ww │ 2021-04-11 11:12:13 │ └────┴──────┴─────────────────────┘ alter table test_rep detach partition '202105' ; ┌─id─┬─name─┬───────────────ctime─┐ │ 3 │ ww │ 2021-04-11 11:12:13 │ └────┴──────┴─────────────────────┘ -- 装载分区 alter table test_rep attach partition '202105' ; ┌─id─┬─name─┬───────────────ctime─┐ │ 1 │ │ 2021-05-19 13:59:49 │ │ 2 │ │ 2021-05-19 13:59:49 │ └────┴──────┴─────────────────────┘ ┌─id─┬─name─┬───────────────ctime─┐ │ 3 │ ww │ 2021-04-11 11:12:13 │ └────┴──────┴─────────────────────┘