1、Clickhouse創建數據庫的語法,如下所示:
1 CREATE DATABASE [IF NOT EXISTS] db_name [ON CLUSTER cluster] [ENGINE = engine(...)]
使用案例,如下所示:
1 master :) CREATE DATABASE IF NOT EXISTS gab_db; 2 3 CREATE DATABASE IF NOT EXISTS gab_db 4 5 Ok. 6 7 0 rows in set. Elapsed: 0.013 sec. 8 9 master :) show databases; 10 11 SHOW DATABASES 12 13 ┌─name───────────────────────────┐ 14 │ _temporary_and_external_tables │ 15 │ default │ 16 │ gab_db │ 17 │ system │ 18 └────────────────────────────────┘ 19 20 4 rows in set. Elapsed: 0.012 sec. 21 22 master :)
2、默認情況下,ClickHouse使用的是原生的數據庫引擎Ordinary(在此數據庫下可以使用任意類型的表引擎,在絕大多數情況下都只需使用默認的數據庫引擎)。當然也可以使用Lazy引擎和MySQL引擎,比如使用MySQL引擎,可以直接在ClickHouse中操作MySQL對應數據庫中的表。假設MySQL中存在一個名為Clickhouse的數據庫,可以使用下面的方式連接MySQL數據庫。
1 -- --------------------------語法----------------------------------- 2 CREATE DATABASE [IF NOT EXISTS] db_name [ON CLUSTER cluster] 3 ENGINE = MySQL('host:port', ['database' | database], 'user', 'password') 4 5 -- --------------------------示例------------------------------------ 6 CREATE DATABASE mysql_db ENGINE = MySQL('192.168.0.109:3306', 'clickhouse', 'root', '123456'); 7 8 9 -- ---------------------------操作----------------------------------- 10 master :) CREATE DATABASE mysql_db ENGINE = MySQL('192.168.0.109:3306', 'clickhouse', 'root', '123456'); 11 12 CREATE DATABASE mysql_db 13 ENGINE = MySQL('192.168.0.109:3306', 'clickhouse', 'root', '123456') 14 15 Ok. 16 17 0 rows in set. Elapsed: 0.011 sec. 18 19 master :) show databases; 20 21 SHOW DATABASES 22 23 ┌─name───────────────────────────┐ 24 │ _temporary_and_external_tables │ 25 │ default │ 26 │ gab_db │ 27 │ mysql_db │ 28 │ system │ 29 └────────────────────────────────┘ 30 31 5 rows in set. Elapsed: 0.006 sec. 32 33 master :) use mysql_db; 34 35 USE mysql_db 36 37 Ok. 38 39 0 rows in set. Elapsed: 0.002 sec. 40 41 master :) show tables; 42 43 SHOW TABLES 44 45 Ok. 46 47 0 rows in set. Elapsed: 0.012 sec. 48 49 master :) show tables; 50 51 SHOW TABLES 52 53 ┌─name────┐ 54 │ user_db │ 55 └─────────┘ 56 57 1 rows in set. Elapsed: 0.011 sec. 58 59 master :) select * from user_db; 60 61 SELECT * 62 FROM user_db 63 64 ┌─id─┬─name─────┬─age─┬─address──────┐ 65 │ 1 │ zhangsan │ 22 │ 河南省新鄉市 │ 66 └────┴──────────┴─────┴──────────────┘ 67 68 1 rows in set. Elapsed: 0.020 sec. 69 70 master :)
如果創建的時候報下面的錯誤,是因為權限的問題,執行下面的命令,解決問題即可。
1 master :) CREATE DATABASE mysql_db ENGINE = MySQL('192.168.0.109:3306', 'clickhouse', 'root', '123456'); 2 3 CREATE DATABASE mysql_db 4 ENGINE = MySQL('192.168.0.109:3306', 'clickhouse', 'root', '123456') 5 6 7 Received exception from server (version 20.8.3): 8 Code: 501. DB::Exception: Received from localhost:9000. DB::Exception: Cannot create MySQL database, because Poco::Exception. Code: 1000, e.code() = 1045, e.displayText() = mysqlxx::ConnectionFailed: Access denied for user 'root'@'192.168.0.109' (using password: YES) ((nullptr):3306), 9 10 0 rows in set. Elapsed: 0.042 sec.
執行下面兩行命令,解決問題即可。
1 grant all privileges on *.* to root@'%' identified by '123456'; 2 3 FLUSH PRIVILEGES;
3、Clickhouse創建數據表的,語法如下所示:
1 CREATE TABLE [IF NOT EXISTS] [db.]table_name [ON CLUSTER cluster] 2 ( 3 name1 [type1] [DEFAULT|MATERIALIZED|ALIAS expr1] [compression_codec] [TTL expr1], 4 name2 [type2] [DEFAULT|MATERIALIZED|ALIAS expr2] [compression_codec] [TTL expr2], 5 ... 6 ) ENGINE = engine
使用案例,如下所示:
1 master :) 2 master :) show tables; 3 4 SHOW TABLES 5 6 Ok. 7 8 0 rows in set. Elapsed: 0.008 sec. 9 10 master :) create table user_db( 11 :-] id Int32, 12 :-] name String 13 :-] )engine=Memory; 14 15 CREATE TABLE user_db 16 ( 17 `id` Int32, 18 `name` String 19 ) 20 ENGINE = Memory 21 22 Ok. 23 24 0 rows in set. Elapsed: 0.003 sec. 25 26 master :) show tables; 27 28 SHOW TABLES 29 30 ┌─name────┐ 31 │ user_db │ 32 └─────────┘ 33 34 1 rows in set. Elapsed: 0.007 sec. 35 36 master :)
上面命令是創建了一張內存表,即使用的是Memory引擎。表引擎決定了數據表的特性,也決定了數據將會被如何存儲及加載。Memory引擎是ClickHouse最簡單的表引擎,數據只會被保存在內存中,在服務重啟時數據會丟失。
4、Clickhouse的數據類型,在創建數據表的時候指定字段的數據類型,數據類型在使用的時候是區分大小寫的,所以在定義字段的時候一定注意數據類型的書寫。
4.1、整數數據類型Int Ranges ,Clickhouse直接使用Int8、Int16、Int32、Int64指代4種大小的Int類型,其末尾的數據正好表明了占用字節的大小(1個節點 = 8位)。
名稱 | 大小(字節) | 范圍 | 普遍觀念 |
Int8 | 1個字節 | -128到127 | Tinyint |
Int16 | 2個字節 | -32768到32767 | Smallint |
Int32 | 4個字節 | -2147483648到2147483647 | int |
Int64 | 8個字節 | -9223372036854775808到9223372036854775807 | Bigint |
具體對應關系,如下所示:
Int8 - [-128 : 127] Int16 - [-32768 : 32767] Int32 - [-2147483648 : 2147483647] Int64 - [-9223372036854775808 : 9223372036854775807]
整數數據類型Uint Ranges,Clickhouse支持無符號的整數,使用前綴U表示,都表示的是正數,即無負數表示。
UInt8 - [0 : 255] UInt16 - [0 : 65535] UInt32 - [0 : 4294967295] UInt64 - [0 : 18446744073709551615]
使用案例,如下所示:
1 master :) create table tb_name( 2 :-] id UInt8 , -- 指定數據類型 3 :-] age UInt8 , -- 指定數據類型 4 :-] flow Int64 -- 指定數據類型 5 :-] ) engine=Log ; -- 指定表引擎 6 7 CREATE TABLE tb_name 8 ( 9 `id` UInt8, 10 `age` UInt8, 11 `flow` Int64 12 ) 13 ENGINE = Log 14 15 Ok. 16 17 0 rows in set. Elapsed: 0.004 sec. 18 19 master :)
4.2、小數數據類型。
Float32 - float,注意:和我們之前的認知是一樣的,這種數據類型在數據特別精准的情況下可能出現數據精度問題。 Float64 - double Decimal(P,S) Decimal32(s) Decimal64(s) ) Decimal128(s)。
名稱 | 大小(字節) | 有效精度(位數) | 普遍概念 |
Float32 | 4個字節 | 7位 | Float |
Float64 | 8個字節 | 16位 | Double |
Select 8.0/0 INF表示的是正無窮,Select -8.0/0 INF表示負無窮,Select 0/0 NAN表示非數字。
使用案例,如下所示:
1 master :) create table tb_user(
2 :-] uid Int8 ,
3 :-] sal Decimal32(2)-- 指定2位小數點 4 :-] ) engine=TinyLog ;
5
6 CREATE TABLE tb_user
7 (
8 `uid` Int8,
9 `sal` Decimal32(2)
10 )
11 ENGINE = TinyLog
12
13 Ok.
14
15 0 rows in set. Elapsed: 0.018 sec.
16
17 master :) insert into tb_user values(1,10000),(2,30000),(3,2000) ;
18
19 INSERT INTO tb_user VALUES
20
21 Ok.
22
23 3 rows in set. Elapsed: 0.053 sec.
24
25 master :) select * from tb_user;
26
27 SELECT *
28 FROM tb_user
29
30 ┌─uid─┬──────sal─┐
31 │ 1 │ 10000.00 │
32 │ 2 │ 30000.00 │
33 │ 3 │ 2000.00 │
34 └─────┴──────────┘
35
36 3 rows in set. Elapsed: 0.009 sec.
37
38 master :)
Decimal如果要求高精度的數值運算,則需要使用定點數。Clickhouse提供了Decimal32、Decimal64和Decimal128三種精度的定點數。可以通過兩種行式表明定點,簡寫方式有Decimal32(S)、Decimal64(S)、Decimal128(S)三種,原生方式為Decimal(P,S),其中,P代表了精度,決定總位數(整數部分+ 小數部分),取值范圍是1~38,S代表規模,決定小數位,取值范圍是0~P。
名稱 | 等效聲明 | 范圍 |
Decimal32(S) | Decimal(1 ~ 9,S) | -1 * 10^(9-S) 到 1 * 10^(9-S) |
Decimal64(S) | Decimal(10 ~ 18,S) | -1 * 10^(18-S) 到 1 * 10^(18-S) |
Decimal128(S) | Decimal(19 ~ 38,S) | -1 * 10^(38-S) 到 1 * 10^(38-S) |
在使用兩個不同精度的定點數進行四則運算的時候,它們的小數點,位數S會發生變化。
在進行加法運算的時候,S取最大值,例如下面的查詢toDecimal64(2,4)與toDecimal32(2,2)相加后S=4;
在進行減法運算的時候,S取最大值,例如下面的查詢toDecimal(2,4)與toDecimal32(2,2)相減后S=4;
在進行乘法運算的時候,S取最大值,例如下面的查詢toDecimal(2,4)與toDecimal32(2,2)相乘后S=4+2;
在進行除法運算的時候,S取最大值,例如下面的查詢toDecimal(2,4)與toDecimal32(2,2)相除后S=4;
但是要保證被除數的S大於除數的S,否則會報錯。
4.3、boolean類型,Clickhouse中沒有對布爾類型進行支持,可以使用0 和1 來代表布爾數據類型。
4.4、字符串數據類型,字符串類型可以細分為String、FixedString、UUID三類,從命名來看彷佛是由一款數據庫提供的類型,反而更像一門編程語言的設計,Clickhouse語法具備編程語言的特征(數據+運算)。
a)、String,字符串由String定義,長度不限,因此在使用String的時候無須聲明大小。它完全代替了傳統意義上數據庫的Varchar、Text、Clob和Blob等字符類型。String類型不限定字符集,因為它根本就沒有這個概念,所以可以將任意編碼的字符串存入其中。但是為了程序的規范性和可維護性,在同一套程序中應該遵守使用統一的編碼,例如,統一使用UTF-8編碼就是一種很好的約定。所以在對數據操作的時候我們不再需要去關注編碼和亂碼問題。
b)、FixedString,類型和傳統意義上的Char類型有些類似,對於一些字符有明確長度的場合,可以使用固定長度的字符串。定長字符串通過FixedString(N)聲明,其中N表示字符串長度,但是與Char不同的是,FixedString使用Null字節填充末尾字符,而Char通常使用空格填充。
String -- 字符串數據類型 一般情況下使用String;類型就可以
FixedString(n) -- 固定長度的數據類型
使用案例,如下所示:
1 master :) drop table if exists tb_stu ; 2 3 DROP TABLE IF EXISTS tb_stu 4 5 Ok. 6 7 0 rows in set. Elapsed: 0.013 sec. 8 9 master :) create table if not exists tb_stu( 10 :-] sid FixedString(8) , 11 :-] name String , 12 :-] address String 13 :-] ) engine = TinyLog ; 14 15 CREATE TABLE IF NOT EXISTS tb_stu 16 ( 17 `sid` FixedString(8), 18 `name` String, 19 `address` String 20 ) 21 ENGINE = TinyLog 22 23 Ok. 24 25 0 rows in set. Elapsed: 0.013 sec. 26 27 master :) 28 master :) insert into tb_stu values('aaaaaaaa' , 'HANGGE' ,'ZhongNanHai') ; 29 30 INSERT INTO tb_stu VALUES 31 32 Ok. 33 34 1 rows in set. Elapsed: 0.011 sec. 35 36 master :) select * from tb_stu; 37 38 SELECT * 39 FROM tb_stu 40 41 ┌─sid──────┬─name───┬─address─────┐ 42 │ aaaaaaaa │ HANGGE │ ZhongNanHai │ 43 └──────────┴────────┴─────────────┘ 44 45 1 rows in set. Elapsed: 0.008 sec. 46 47 master :)
4.5、UUID隨機的一串字符串。
1 master :) drop table if exists tb_uuid ; 2 3 DROP TABLE IF EXISTS tb_uuid 4 5 Ok. 6 7 0 rows in set. Elapsed: 0.002 sec. 8 9 master :) create table tb_uuid( 10 :-] id UUID , 11 :-] name String 12 :-] ) engine = TinyLog ; 13 14 CREATE TABLE tb_uuid 15 ( 16 `id` UUID, 17 `name` String 18 ) 19 ENGINE = TinyLog 20 21 Ok. 22 23 0 rows in set. Elapsed: 0.003 sec. 24 25 master :) 26 master :) insert into tb_uuid (name) values ('zss') , ('lss') ,('daa') ; 27 28 INSERT INTO tb_uuid (name) VALUES 29 30 Ok. 31 32 3 rows in set. Elapsed: 0.004 sec. 33 34 master :) insert into tb_uuid select generateUUIDv4() , 'HANGGE' ; 35 36 INSERT INTO tb_uuid SELECT 37 generateUUIDv4(), 38 'HANGGE' 39 40 Ok. 41 42 0 rows in set. Elapsed: 0.010 sec. 43 44 master :) select * from tb_uuid; 45 46 SELECT * 47 FROM tb_uuid 48 49 ┌───────────────────────────────────id─┬─name───┐ 50 │ 00000000-0000-0000-0000-000000000000 │ zss │ 51 │ 00000000-0000-0000-0000-000000000000 │ lss │ 52 │ 00000000-0000-0000-0000-000000000000 │ daa │ 53 │ c712b9e8-1c6c-4614-a836-f85da3de62aa │ HANGGE │ 54 └──────────────────────────────────────┴────────┘ 55 56 4 rows in set. Elapsed: 0.008 sec. 57 58 master :)
4.6、枚舉類型,包括 Enum8 和 Enum16 類型。Enum 保存 'string'= integer 的對應關系。Enum8 用 'String'= Int8 對描述。Enum16 用 'String'= Int16 對描述。
用法演示,創建一個帶有一個枚舉 Enum8('hello' = 1, 'world' = 2) 類型的列:
1 master :) CREATE TABLE t_enum 2 :-] ( 3 :-] x Enum8('hello' = 1, 'world' = 2) 4 :-] ) 5 :-] ENGINE = TinyLog; 6 7 CREATE TABLE t_enum 8 ( 9 `x` Enum8('hello' = 1, 'world' = 2) 10 ) 11 ENGINE = TinyLog 12 13 Ok. 14 15 0 rows in set. Elapsed: 0.008 sec. 16 17 master :) 18 19 -- 這個 x 列只能存儲類型定義中列出的值:'hello'或'world'。如果嘗試保存任何其他值,ClickHouse 拋出異常。 20 master :) INSERT INTO t_enum VALUES ('hello'), ('world'), ('hello') 21 :-] ; 22 23 INSERT INTO t_enum VALUES 24 25 Ok. 26 27 3 rows in set. Elapsed: 0.006 sec. 28 29 master :) INSERT INTO t_enum VALUES; 30 31 INSERT INTO t_enum VALUES 32 33 Ok. 34 35 0 rows in set. Elapsed: 0.004 sec. 36 37 master :) insert into t_enum values('a') 38 :-] ; 39 40 INSERT INTO t_enum VALUES 41 42 43 Exception on client: 44 Code: 36. DB::Exception: Unknown element 'a' for type Enum8('hello' = 1, 'world' = 2) 45 46 Connecting to localhost:9000 as user default. 47 Connected to ClickHouse server version 20.8.3 revision 54438. 48 49 master :) 50 51 52 -- 從表中查詢數據時,ClickHouse 從 Enum 中輸出字符串值。 53 master :) select * from t_enum; 54 55 SELECT * 56 FROM t_enum 57 58 ┌─x─────┐ 59 │ hello │ 60 │ world │ 61 │ hello │ 62 └───────┘ 63 64 3 rows in set. Elapsed: 0.009 sec. 65 66 master :) 67 68 69 -- 如果需要看到對應行的數值,則必須將 Enum 值轉換為整數類型。cast 強制數據類型轉換... 將枚舉類型字段轉換成Int8數據類型 70 master :) SELECT CAST(x, 'Int8') FROM t_enum 71 :-] ; 72 73 SELECT CAST(x, 'Int8') 74 FROM t_enum 75 76 ┌─CAST(x, 'Int8')─┐ 77 │ 1 │ 78 │ 2 │ 79 │ 1 │ 80 └─────────────────┘ 81 82 3 rows in set. Elapsed: 0.006 sec. 83 84 master :)
4.7、數組數據類型。Array(T):由 T 類型元素組成的數組。其中,T 可以是任意類型,包含數組類型。 但不推薦使用多維數組,ClickHouse 對多維數組的支持有限。
例如,不能在 MergeTree 表中存儲多維數組。
Clickhouse支持數組這種復合數據類型,並且數據操作在數據分析中起到非常便利的效果,數組的定義方式有兩種:
第一種是array(T),泛型的方式。
第二種是直接插入數據的行式[e1,e2,e3.....],我們在這里要求數組中的數據類型是一致的,數組是強數據類型。
使用案例,如下所示:
1 master :) SELECT array(1, 2) AS x, toTypeName(x); 2 3 SELECT 4 [1, 2] AS x, 5 toTypeName(x) 6 7 ┌─x─────┬─toTypeName(array(1, 2))─┐ 8 │ [1,2] │ Array(UInt8) │ 9 └───────┴─────────────────────────┘ 10 11 1 rows in set. Elapsed: 0.022 sec. 12 13 master :) SELECT [1, 2] AS x, toTypeName(x); 14 15 SELECT 16 [1, 2] AS x, 17 toTypeName(x) 18 19 ┌─x─────┬─toTypeName([1, 2])─┐ 20 │ [1,2] │ Array(UInt8) │ 21 └───────┴────────────────────┘ 22 23 1 rows in set. Elapsed: 0.009 sec. 24 25 26 -- 數組的取值,從1開始取值,中括號里面從1開始,就可以取出數組的第一個值。 27 28 master :) SELECT ['a', 'b', 'c'][1] 29 :-] ; 30 31 SELECT ['a', 'b', 'c'][1] 32 33 ┌─arrayElement(['a', 'b', 'c'], 1)─┐ 34 │ a │ 35 └──────────────────────────────────┘ 36 37 1 rows in set. Elapsed: 0.006 sec. 38 39 master :) select array('a','b','c')[2]; 40 41 SELECT ['a', 'b', 'c'][2] 42 43 ┌─arrayElement(array('a', 'b', 'c'), 2)─┐ 44 │ b │ 45 └───────────────────────────────────────┘ 46 47 1 rows in set. Elapsed: 0.007 sec. 48 49 master :)
如果要創建Array數組類型的字段,需要使用()來指定泛型,比如Array(String),如下所示:
1 master :) 2 master :) CREATE TABLE tb_array 3 :-] ( 4 :-] `id` UInt8, 5 :-] `name` String, 6 :-] `hobby` Array(String) 7 :-] )ENGINE = Log; 8 9 CREATE TABLE tb_array 10 ( 11 `id` UInt8, 12 `name` String, 13 `hobby` Array(String) 14 ) 15 ENGINE = Log 16 17 Ok. 18 19 0 rows in set. Elapsed: 0.029 sec. 20 21 master :) desc tb_array; 22 23 DESCRIBE TABLE tb_array 24 25 ┌─name──┬─type──────────┬─default_type─┬─default_expression─┬─comment─┬─codec_expression─┬─ttl_expression─┐ 26 │ id │ UInt8 │ │ │ │ │ │ 27 │ name │ String │ │ │ │ │ │ 28 │ hobby │ Array(String) │ │ │ │ │ │ 29 └───────┴───────────────┴──────────────┴────────────────────┴─────────┴──────────────────┴────────────────┘ 30 31 3 rows in set. Elapsed: 0.014 sec. 32 33 master :) insert into tb_array values(1,'張三',['抽煙','喝酒','燙頭']),(2,'岳岳',['說相聲','唱歌']); 34 35 INSERT INTO tb_array VALUES 36 37 Ok. 38 39 2 rows in set. Elapsed: 0.045 sec. 40 41 master :) 42 master :) select * from tb_array; 43 44 SELECT * 45 FROM tb_array 46 47 ┌─id─┬─name─┬─hobby──────────────────┐ 48 │ 1 │ 張三 │ ['抽煙','喝酒','燙頭'] │ 49 │ 2 │ 岳岳 │ ['說相聲','唱歌'] │ 50 └────┴──────┴────────────────────────┘ 51 52 2 rows in set. Elapsed: 0.071 sec. 53 54 master :)
注意:根據數組創建的數據塊數,會根據服務器的核數來決定創建幾個塊,服務器的核數決定了創建的塊數。
1 總核數 = 物理CPU個數 * 每顆物理CPU的核數。 2 總邏輯CPU數 = 物理CPU個數 * 每顆物理CPU的核數 * 超線程數。 3 4 查看物理CPU個數。 5 cat /proc/cpuinfo | grep "physical id" | sort | uniq | wc -l 6 7 查看每個物理CPU中的core的個數即核數。 8 cat /proc/cpuinfo | grep "cpu cores" |uniq 9 10 查看邏輯CPU的個數 11 cat /proc/cpuinfo | grep "processor" | wc -l
數組居然還支持高階函數,類似Java的lambda表達式,也是很強大的東西了,如下所示:
注意:Clickhouse的字符串不能使用雙引號引起來,只能使用單引號引起來。
1 master :) 2 master :) select arrayMap(e -> concat(e,'lambda'),hobby) from tb_array; 3 4 SELECT arrayMap(e -> concat(e, 'lambda'), hobby) 5 FROM tb_array 6 7 ┌─arrayMap(lambda(tuple(e), concat(e, 'lambda')), hobby)─┐ 8 │ ['抽煙lambda','喝酒lambda','燙頭lambda'] │ 9 │ ['說相聲lambda','唱歌lambda'] │ 10 └────────────────────────────────────────────────────────┘ 11 12 2 rows in set. Elapsed: 0.048 sec. 13 14 master :)
4.8、Nested數據類型,Nested(name1 Type1, Name2 Type2, …)。
Nested是一種嵌套表結構,一張數據表,可以定義任意多個嵌套類型字段,但是每個字段的嵌套層級只支持一級,即嵌套表內不能繼續使用嵌套類型,對於簡單場景的層級關系或者關聯關系,使用嵌套類型也是一個不錯的選擇。
Nested嵌套類型本質是一種多維數組的結構,嵌套表中的每個字段的都是一個數組,並且行與行之間數組的長度無須對齊,但是需要注意的是,在同一行數據內每個數組字段的長度必須相等。
1 master :) 2 master :) CREATE TABLE tb_nested 3 :-] ( 4 :-] `id` String, 5 :-] `user` Nested( uid Int, name String, age UInt8) 6 :-] )ENGINE = TinyLog; 7 8 CREATE TABLE tb_nested 9 ( 10 `id` String, 11 `user` Nested( uid Int, name String, age UInt8) 12 ) 13 ENGINE = TinyLog 14 15 Ok. 16 17 0 rows in set. Elapsed: 0.010 sec. 18 19 master :) desc tb_nested ; 20 21 DESCRIBE TABLE tb_nested 22 23 ┌─name──────┬─type──────────┬─default_type─┬─default_expression─┬─comment─┬─codec_expression─┬─ttl_expression─┐ 24 │ id │ String │ │ │ │ │ │ 25 │ user.uid │ Array(Int32) │ │ │ │ │ │ 26 │ user.name │ Array(String) │ │ │ │ │ │ 27 │ user.age │ Array(UInt8) │ │ │ │ │ │ 28 └───────────┴───────────────┴──────────────┴────────────────────┴─────────┴──────────────────┴────────────────┘ 29 30 4 rows in set. Elapsed: 0.012 sec. 31 32 master :)
插入數據,進行簡單的測試,如下所示:
1 master :) insert into tb_nested values(1 , [1,2,3],['zss','lss','ymm'],[21,33,18]) ; 2 3 INSERT INTO tb_nested VALUES 4 5 Ok. 6 7 1 rows in set. Elapsed: 0.007 sec. 8 9 master :) SELECT 10 :-] user.uid, 11 :-] user.name 12 :-] FROM tb_nested; 13 14 SELECT 15 user.uid, 16 user.name 17 FROM tb_nested 18 19 ┌─user.uid─┬─user.name───────────┐ 20 │ [1,2,3] │ ['zss','lss','ymm'] │ 21 └──────────┴─────────────────────┘ 22 23 1 rows in set. Elapsed: 0.008 sec. 24 25 master :)
4.9、元組,Tuple(T1, T2, ...):元組,其中每個元素都有單獨的類型。
Tuple元組數據類型,是一個特殊的數據類型,可以理解為集合,可以存儲任意的數據類型,這一點區別於數組。在定義的時候需要聲明數據類型和數據元素的個數。
數據類型由1~n個元素組成,每個元素之間允許設置不同的數據類型,且彼此之間不要求兼容。元素同樣支持類型推斷,其推斷依據仍然以最小存儲代價為原則。與數據類型,元組也可以使用兩種方式定義,常規方式是tuple(T),元組中可以存儲多種數據類型,但是要注意數據類型的順序。
使用案例,如下所示:
1 master :) 2 master :) SELECT tuple(1,'a') AS x, toTypeName(x); # SELECT tuple(1,'a',12.23)可以簡寫為SELECT (1,'a',12.23) 3 4 SELECT 5 (1, 'a') AS x, 6 toTypeName(x) 7 8 ┌─x───────┬─toTypeName(tuple(1, 'a'))─┐ 9 │ (1,'a') │ Tuple(UInt8, String) │ 10 └─────────┴───────────────────────────┘ 11 12 1 rows in set. Elapsed: 0.008 sec. 13 14 master :)
注意:創建數據表的時候使用元組的時候,需要指定元素的數據類型。
1 master :) 2 master :) CREATE TABLE tb_tuple 3 :-] ( 4 :-] `id` UInt8, 5 :-] `t1` Tuple(String,Int8,Date) 6 :-] )ENGINE = Log; 7 8 CREATE TABLE tb_tuple 9 ( 10 `id` UInt8, 11 `t1` Tuple(String, Int8, Date) 12 ) 13 ENGINE = Log 14 15 Ok. 16 17 0 rows in set. Elapsed: 0.066 sec. 18 19 master :) insert into tb_tuple values(1, ('red',25,'1994-05-18')); 20 21 INSERT INTO tb_tuple VALUES 22 23 Ok. 24 25 1 rows in set. Elapsed: 0.145 sec. 26 27 master :) select * from tb_tuple; 28 29 SELECT * 30 FROM tb_tuple 31 32 ┌─id─┬─t1──────────────────────┐ 33 │ 1 │ ('red',25,'1994-05-18') │ 34 └────┴─────────────────────────┘ 35 36 1 rows in set. Elapsed: 0.033 sec. 37 38 master :)
4.10、Date日期類型、DateTime日期時間類型,支持符合格式的字符串類型的插入。
DateTime64可以記錄亞秒,它在DateTime之上增加了精度的設置,在指定數據類型的時候可以使用DateTime64(2)指定兩位精度。
1 master :) 2 master :) CREATE TABLE tb_name 3 :-] ( 4 :-] `id` UInt8, 5 :-] `age` UInt8, 6 :-] `birthday` Date, 7 :-] `updateTime` DateTime 8 :-] )ENGINE = Log; 9 10 CREATE TABLE tb_name 11 ( 12 `id` UInt8, 13 `age` UInt8, 14 `birthday` Date, 15 `updateTime` DateTime 16 ) 17 ENGINE = Log 18 19 Ok. 20 21 0 rows in set. Elapsed: 0.055 sec. 22 23 master :) 24 master :) insert into tb_name values(1,22,'1994-05-16','2021-02-20 14:21:30'),(2,24,'1994-05-17','2021-02-20 14:21:30'); 25 26 INSERT INTO tb_name VALUES 27 28 Ok. 29 30 2 rows in set. Elapsed: 0.065 sec. 31 32 master :) select * from tb_name; 33 34 SELECT * 35 FROM tb_name 36 37 ┌─id─┬─age─┬───birthday─┬──────────updateTime─┐ 38 │ 1 │ 22 │ 1994-05-16 │ 2021-02-20 14:21:30 │ 39 │ 2 │ 24 │ 1994-05-17 │ 2021-02-20 14:21:30 │ 40 └────┴─────┴────────────┴─────────────────────┘ 41 42 2 rows in set. Elapsed: 0.010 sec. 43 44 master :)
4.11、Enum枚舉類型,Clickhouse支持枚舉類型,這是一種在定義常量的時候經常會使用的數據類型,Clickhouse提供了Enum8和Enum16兩種枚舉類型,他們除了取值范圍不同之外,別無二致。枚舉固定使用(String:Int),這種Key/Value鍵值對的行式定義數據,所以Enum8和Enum16分別會對應(String:Int8)和(String:Int16)。
1 master :) 2 master :) CREATE TABLE tb_enum 3 :-] ( 4 :-] `id` UInt8, 5 :-] `color` Enum('red' = 1,'green' = 2, 'blue' = 3) 6 :-] )ENGINE = Log; 7 8 CREATE TABLE tb_enum 9 ( 10 `id` UInt8, 11 `color` Enum('red' = 1, 'green' = 2, 'blue' = 3) 12 ) 13 ENGINE = Log 14 15 Ok. 16 17 0 rows in set. Elapsed: 0.034 sec. 18 19 master :) insert into tb_enum values(1,'red'),(2,'green'),(3,'blue'); 20 21 INSERT INTO tb_enum VALUES 22 23 Ok. 24 25 3 rows in set. Elapsed: 0.055 sec. 26 27 master :) insert into tb_enum values(4,1),(5,2),(6,3); 28 29 INSERT INTO tb_enum VALUES 30 31 Ok. 32 33 3 rows in set. Elapsed: 0.035 sec. 34 35 master :)
4.12、Domain(pojo、beans實體類)里面的IPv4數據類型,域名分為IPv4和IPv6兩類,本質上它們是對整數和字符串的進一步封裝,其中IPv4類型是基於UInt32封裝的。
1)、出於便捷性的考量,例如IPv4類型支持格式檢查,格式錯誤的IP數據是無法被寫入的。
2)、出於性能的考量,同樣以IPv4為例,IPv4使用UInt32存儲,相對String更加緊湊,占用空間更小,查詢性能更快。IPv6類型是基於FixedString(16)封裝的,它的使用彷佛與IPv4別無二致,在使用Domain類型的時候還有一點需要注意,雖然它從表象上看起來與String一樣,但是Domain類型並不是字符串,所以它不支持隱式的自動類型轉換。如果需要返回IP的字符串行式,需要顯示調用IPv4NumToString或者IPv6NumToString函數進行轉換。
1 master :) 2 master :) CREATE TABLE tb_domin 3 :-] ( 4 :-] `id` UInt8, 5 :-] `ip` IPv4 6 :-] )ENGINE = Log; 7 8 CREATE TABLE tb_domin 9 ( 10 `id` UInt8, 11 `ip` IPv4 12 ) 13 ENGINE = Log 14 15 Ok. 16 17 0 rows in set. Elapsed: 0.024 sec. 18 19 master :) insert into tb_domin values(1, '192.168.110.133'); 20 21 INSERT INTO tb_domin VALUES 22 23 Ok. 24 25 1 rows in set. Elapsed: 0.058 sec. 26 27 master :) insert into tb_domin values(1, '192.168.110.133'); 28 29 INSERT INTO tb_domin VALUES 30 31 Ok. 32 33 1 rows in set. Elapsed: 0.006 sec. 34 35 master :) select * from tb_domin; 36 37 SELECT * 38 FROM tb_domin 39 40 ┌─id─┬──────────────ip─┐ 41 │ 1 │ 192.168.110.133 │ 42 └────┴─────────────────┘ 43 ┌─id─┬──────────────ip─┐ 44 │ 1 │ 192.168.110.133 │ 45 └────┴─────────────────┘ 46 47 2 rows in set. Elapsed: 0.025 sec. 48 49 master :)
5、Clickhouse為什么可以這么快?主要特點,如下所示:
1)、開發語言是C++,可以更好的利用硬件優勢來提升數據處理的效率。
2)、摒棄了hadoop生態體系。
3)、數據底層以列式數據存儲。
4)、可以利用單節點的多核並行處理。
5)、為數據建立索引,分為一級索引、二級索引、稀疏索引。
6)、使用大量高效率算法處理數據。
7)、支持向量化處理數據。
8)、支持預先運算模型,預先計算,等等優勢。
6、Clickhouse的引擎分為數據庫引擎和數據表引擎,數據表的引擎,不同的引擎決定數據庫的類型,Clickhouse的數據庫引擎的作用。
1)、引擎決定了數據存儲位置。
2)、數據組織結構。
3)、是否分塊、是否索引、是否持久化操作。
4)、是否可以並發讀寫。
5)、是否支持副本操作、是否支持索引。
6)、是否支持分布式。
7、Clickhouse的數據表引擎(即表的類型)決定了的特征,如下所示:
1)、數據的存儲方式和位置,寫到哪里以及從那里讀取數據。
2)、支持那些查詢以及如何支持。
3)、並發數據訪問。
4)、索引的使用(如果存在)。
5)、是否可以執行多線程請求。
6)、數據復制參數。在讀取時候,引擎只需要輸出所請求的列,但在某些情況下,引擎可以在響應請求時部分處理數據。對於大多數正式的任務,應該使用MergeTree族中的引擎。
8、數據庫,數據庫起到了命名空間的作用,可以有效規避命名沖突的問題,也是為后續的數據隔離提供了支撐。任何一張數據表,都必須歸屬在某個數據庫之下。在Clickhouse中數據庫也有自己的引擎,數據庫目前支持的數據庫引擎有6種,如下所示:
1)、Ordinary,默認引擎,在絕大多數情況下我們都會使用默認引擎,使用的時候無須刻意聲明。在此數據庫下可以使用任意類型的表引擎。
2)、Dictionary,字段引擎,此類數據庫會自動為所有數據字典創建它們的數據表。
3)、Memory,內存引擎,了解即可,用於存放臨時數據,此類數據庫下的數據表只會停留在內存中,不會設計任何磁盤操作,當服務重啟后數據會被清除。
4)、Lazy,日志引擎,此類數據庫下只能使用Log系列的表引擎。
5)、Mysql,Mysql數據庫的引擎,此類數據庫下會自動拉取遠端Mysql數據庫中的數據,並為他們創建Mysql表引擎的數據表。
6)、MaterializeMySQL,主要做Mysql的數據同步,Clickhouse 20.8將新增 MaterializeMySQL引擎 ,可通過binlog日志實時物化mysql數據,極大提升了數倉的查詢性能和數據同步的時效性;原有mysql中承擔的數據分析工作 可交由clickhouse去做,這么做可顯著降低線上mysql的負載,從此OLTP與OLAP業務實現完美融合。
9、Clickhouse的數據表引擎,具體分類,如下所示:
9.1)、Log日志引擎,具有最小功能的輕量級引擎。當您需要快速寫入許多小表(最多約100萬行)並在以后整體讀取它們時,該類型的引擎是最有效的。具體表現為,比較簡單,數據少,測試使用,Log家族都屬於本地表(在/var/lib/clickhouse/data下面),本地存儲表數據。
1)、TinyLog引擎(數據不分快)。最簡單的數據表引擎,用於將數據存儲在磁盤上。每列都存儲在單獨的壓縮文件中,寫入的時候,數據將附加到文件末尾。該引擎沒有並發控制,只支持並發讀。如果同時從表中讀取和寫入數據,則讀取操作將拋出異常。如果同時寫入多個查詢中的表,則數據將被破壞。
注意:TinyLog引擎(數據不分快)引擎,*.bin每個字段的壓縮數據,數據插入時會進行追加數據。sizes.json文件,顯示每個字段文件的大小。該引擎的特點,沒有數據塊,不能並行操作,不能同時讀寫操作,沒有索引,寫是追加寫,數據以列字段文件存儲。
1 master :) 2 master :) 3 master :) CREATE TABLE tb_tinyLog 4 :-] ( 5 :-] `id` UInt8, 6 :-] `log_name` String 7 :-] )ENGINE = TinyLog; 8 9 CREATE TABLE tb_tinyLog 10 ( 11 `id` UInt8, 12 `log_name` String 13 ) 14 ENGINE = TinyLog 15 16 Ok. 17 18 0 rows in set. Elapsed: 0.016 sec. 19 20 master :) insert into tb_tinyLog values(1, '張三三'); 21 22 INSERT INTO tb_tinyLog VALUES 23 24 Ok. 25 26 1 rows in set. Elapsed: 0.027 sec. 27 28 master :) select * from tb_tinyLog; 29 30 SELECT * 31 FROM tb_tinyLog 32 33 ┌─id─┬─log_name─┐ 34 │ 1 │ 張三三 │ 35 └────┴──────────┘ 36 37 1 rows in set. Elapsed: 0.010 sec. 38 39 master :)
2)、StripeLog引擎,數據分塊列在一起,在你需要寫入許多小數據量(小於一百萬行)的表的場景下使用這個引擎。
3)、Log引擎。
9.2)、MergeTree引擎,主要包含下面幾種。
1)、MergeTree()。
2)、ReplacingMergeTree。
3)、SummingMergeTree引擎,將相同主鍵的數據分區內合並指定字段進行累加。
4)、CollapsingMergeTree,ClickHouse實現了CollapsingMergeTree來消除ReplacingMergeTree的限制(只刪除小版本字段的問題)。該引擎要求在建表語句中指定一個標記列Sign,后台Compaction時會將主鍵相同、Sign相反的行進行折疊,也即刪除。
CollapsingMergeTree雖然解決了主鍵相同的數據即時刪除的問題,但是狀態持續變化且多線程並行寫入情況下,狀態行與取消行位置可能亂序,導致無法正常折疊。只有保證老的狀態行在在取消行的上面, 新的狀態行在取消行的下面,但是多線程無法保證寫的順序。
5)、VersionedCollapsingMergeTree,取消字段和數據版本同事使用,避免取消行數據無法刪除的問題,為了解決CollapsingMergeTree亂序寫入情況下無法正常折疊問題,VersionedCollapsingMergeTree表引擎在建表語句中新增了一列Version,用於在亂序情況下記錄狀態行與取消行的對應關系。主鍵相同,且Version相同、Sign相反的行,在Compaction時會被刪除。與CollapsingMergeTree類似, 為了獲得正確結果,業務層需要改寫SQL,將count()、sum(col)分別改寫為sum(Sign)、sum(col * Sign)。