Clickhouse基礎語法、數據類型、數據表引擎學習


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 │
15default16 │ 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 │
25default26 │ 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──────┐
651 │ 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─┐
31110000.0032230000.003332000.0034 └─────┴──────────┘
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───┐
5000000000-0000-0000-0000-000000000000 │ zss    │
5100000000-0000-0000-0000-000000000000 │ lss    │
5200000000-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')─┐
77178279180 └─────────────────┘
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──────────────────┐
481 │ 張三 │ ['抽煙','喝酒','燙頭'] │
492 │ 岳岳 │ ['說相聲','唱歌']      │
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──────────────────────┐
331 │ ('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─┐
381221994-05-162021-02-20 14:21:30392241994-05-172021-02-20 14:21:3040 └────┴─────┴────────────┴─────────────────────┘
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─┐
411192.168.110.13342 └────┴─────────────────┘
43 ┌─id─┬──────────────ip─┐
441192.168.110.13345 └────┴─────────────────┘
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─┐
341 │ 張三三   │
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)。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM