ClickHouse筆記
尚硅谷clickhouse學習筆記
第 1 章 ClickHouse 入門
官方文檔
-
ClickHouse 是開源的列式存儲數據庫,使用C++編寫,主要用於在線分析處理查詢(OLAP),使用SQL查詢實時生成分析析數據報 告。
-
列式儲存的好處:
➢ 對於列的聚合,計數,求和等統計操作原因優於行式存儲。
➢ 由於某一列的數據類型都是相同的,針對於數據存儲更容易進行數據壓縮,每一列 選擇更優的數據壓縮算法,大大提高了數據的壓縮比重。
➢ 由於數據壓縮比更好,一方面節省了磁盤空間,另一方面對於 cache 也有了更大的 發揮空間。
-
ClickHouse 和 MySQL 類似,把表級的存儲引擎插件化,根據表的不同需求可以設定不同 的存儲引擎。目前包括合並樹、日志、接口和其他四大類 20 多種引擎。
-
ClickHouse 采用類 LSM Tree的結構,數據寫入后定期在后台 Compaction。通過類 LSM tree 的結構,ClickHouse 在數據導入時全部是順序 append 寫,寫入后數據段不可更改,在后台 compaction 時也是多個段 merge sort 后順序寫回磁盤。順序寫的特性,充分利用了磁盤的吞 吐能力,即便在 HDD 上也有着優異的寫入性能。
-
ClickHouse 將數據划分為多個 partition,每個 partition 再進一步划分為多個 index granularity(索引粒度),然后通過多個 CPU核心分別處理其中的一部分來實現並行數據處理。 在這種設計下,單條 Query 就能利用整機所有 CPU。極致的並行處理能力,極大的降低了查 詢延時。以對於高 qps 的查詢業務, ClickHouse 並不是強項。
-
ClickHouse不適合關聯查詢,性能較差。
第 2 章 ClickHouse 的安裝
-
關閉防火牆
systemctl stop firewalld #關閉防火牆 systemctl disable firewalld#禁止開機啟動防火牆
-
CentOS 取消打開文件數限制
-
/etc/security/limits.conf 文件的末尾加入以下內容
* soft nofile 65536 * hard nofile 65536 * soft nproc 131072 * hard nproc 131072
-
/etc/security/limits.d/20-nproc.conf 文件的末尾加入以下內容
* soft nofile 65536 * hard nofile 65536 * soft nproc 131072 * hard nproc 131072
-
-
安裝依賴
yum install -y libtool yum install -y *unixODBC*
-
CentOS 取消 SELINUX
修改/etc/selinux/config 中的 SELINUX=disabled
修改這個配置需要重啟,臨時生效命令
setenforce 0
查詢狀態命令getenforce
-
下載安裝包
本次安裝為21.7.3.14-2版本
clickhouse-client-21.7.3.14-2.noarch.rpm
clickhouse-common-static-21.7.3.14-2.x86_64.rpm
clickhouse-common-static-dbg-21.7.3.14-2.x86_64.rpm
clickhouse-server-21.7.3.14-2.noarch.rpm
新建一文件夾,放置上述下載的4個rpm包,在文件夾中執行
rpm -ivh *.rpm
命令進行安裝。過程中需要設置密碼。安裝完成后,執行
rpm -qa|grep clickhouse
進行安裝確認。目錄位置:
bin/ > /usr/bin
conf/> /etc/clickhouse-server/
lib/ ==> /var/lib/clickhouse
log/ ==> /var/log/clickhouse -
配置
- 修改 /etc/clickhouse-server/config.xml。把 :: 的注釋打開,這樣的話才能讓 ClickHouse 被除本 機以外的服務器訪問
- 日志配置也在/etc/clickhouse-server/config.xml這個文件中
-
啟動命令:
clickhouse start
客戶端連接命令:
clickhouse-client -m
,有設置密碼的話使用clickhouse-client -m --password 123456
直接執行命令
clickhouse-client --password 123456 --query "show databases;"
第 3 章 數據類型
-
整型
固定長度的整型,包括有符號整型或無符號整型。
整型范圍(-2n-1~2n-1-1):
Int8 - [-128 : 127]
Int16 - [-32768 : 32767]
Int32 - [-2147483648 : 2147483647]
Int64 - [-9223372036854775808 : 9223372036854775807]
無符號整型范圍(0~2n-1):
UInt8 - [0 : 255]
UInt16 - [0 : 65535]
UInt32 - [0 : 4294967295]
UInt64 - [0 : 18446744073709551615]
-
浮點型
Float32 - float
Float64 – double
-
布爾型
沒有單獨的類型來存儲布爾值。可以使用 UInt8 類型,取值限制為 0 或 1。
-
Decimal 型
有符號的浮點數,可在加、減和乘法運算過程中保持精度。對於除法,最低有效數字會 被丟棄(不舍入)。
有三種聲明:
➢ Decimal32(s),相當於 Decimal(9-s,s),有效位數為 1~9
➢ Decimal64(s),相當於 Decimal(18-s,s),有效位數為 1~18
➢ Decimal128(s),相當於 Decimal(38-s,s),有效位數為 1~38
s 標識小數位
-
字符串
1)String 字符串可以任意長度的。它可以包含任意的字節集,包含空字節。
2)FixedString(N) 固定長度 N 的字符串,N 必須是嚴格的正自然數。當服務端讀取長度小於 N 的字符 串時候,通過在字符串末尾添加空字節來達到 N 字節長度。 當服務端讀取長度大於 N 的 字符串時候,將返回錯誤消息。
-
枚舉類型
包括 Enum8 和 Enum16 類型。Enum 保存 'string'= integer 的對應關系。
Enum8 用 'String'= Int8 對描述。
Enum16 用 'String'= Int16 對描述。
建表示例:
CREATE TABLE t_enum
(
x
Enum8('hello' = 1, 'world' = 2)
)
ENGINE = TinyLog;插入示例:
insert into t_enum values('hello');
insert into t_enum values(2);
-
時間類型
目前 ClickHouse 有三種時間類型
➢ Date 接受年-月-日的字符串比如 ‘2019-12-16’
➢ Datetime 接受年-月-日 時:分:秒的字符串比如 ‘2019-12-16 20:50:10’
➢ Datetime64 接受年-月-日 時:分:秒.亞秒的字符串比如‘2019-12-16 20:50:10.66’
日期類型,用兩個字節存儲,表示從 1970-01-01 (無符號) 到當前的日期值。
-
數組
Array(T):由 T 類型元素組成的數組。 T 可以是任意類型,包含數組類型。 但不推薦使用多維數組,ClickHouse 對多維數組 的支持有限。
第 4 章 表引擎
-
表引擎的使用
表引擎決定了如何存儲表的數據。包括:
➢ 數據的存儲方式和位置,寫到哪里以及從哪里讀取數據。
➢ 支持哪些查詢以及如何支持。
➢ 並發數據訪問。
➢ 索引的使用(如果存在)。
➢ 是否可以執行多線程請求。
➢ 數據復制參數。
表引擎的使用方式就是必須顯式在創建表時定義該表使用的引擎,以及引擎使用的相關 參數。 特別注意:引擎的名稱大小寫敏感
-
TinyLog
以列文件的形式保存在磁盤上,不支持索引,沒有並發控制。一般保存少量數據的小表, 生產環境上作用有限。可以用於平時練習測試用。
-
Memory
內存引擎,數據以未壓縮的原始形式直接保存在內存當中,服務器重啟數據就會消失。 讀寫操作不會相互阻塞,不支持索引。簡單查詢下有非常非常高的性能表現(超過 10G/s)。
-
MergeTree
ClickHouse 中最強大的表引擎當屬 MergeTree(合並樹)引擎及該系列(*MergeTree) 中的其他引擎,支持索引和分區,地位可以相當於 innodb 之於 Mysql。
- 建表語句
create table t_order_mt( id UInt32, sku_id String, total_amount Decimal(16,2), create_time Datetime ) engine =MergeTree partition by toYYYYMMDD(create_time) primary key (id) order by (id,sku_id);
- 插入數據
insert into t_order_mt values (101,'sku_001',1000.00,'2020-06-01 12:00:00') , (102,'sku_002',2000.00,'2020-06-01 11:00:00'), (102,'sku_004',2500.00,'2020-06-01 12:00:00'), (102,'sku_002',2000.00,'2020-06-01 13:00:00'), (102,'sku_002',12000.00,'2020-06-01 13:00:00'), (102,'sku_002',600.00,'2020-06-02 12:00:00');
由於我們按照年月日進行了分區,所以查詢出來會有兩塊
-
partition by 分區(可選)
-
作用
主要是降低掃描的范圍,優化查詢速度
如果不填 只會使用一個分區。
-
分區目錄
MergeTree 是以列文件+索引文件+表定義文件組成的,但是如果設定了分區那么這些文 件就會保存到不同的分區目錄中。
-
並行
分區后,面對涉及跨分區的查詢統計,ClickHouse 會以分區為單位並行處理。
-
數據寫入與分區合並
任何一個批次的數據寫入都會產生一個臨時分區,不會納入任何一個已有的分區。寫入 后的某個時刻(大概 10-15 分鍾后),ClickHouse 會自動執行合並操作(等不及也可以手動 通過 optimize 執行),把臨時分區的數據,合並到已有分區中。
optimize table xxxx final;
實際存儲位置:
數據文件位置:/var/lib/clickhouse/data/default/t_order_mt/20200601_1_1_0
-
primary key 主鍵(可選)
只提供了數據的一級索引,但是卻不 是唯一約束。這就意味着是可以存在相同 primary key 的數據的。
主鍵的設定主要依據是查詢語句中的 where 條件。
根據條件通過對主鍵進行某種形式的二分查找,能夠定位到對應的 index granularity,避 免了全表掃描。
index granularity: 直接翻譯的話就是索引粒度,指在稀疏索引中兩個相鄰索引對應數 據的間隔。ClickHouse 中的 MergeTree 默認是 8192。
稀疏索引:
稀疏索引的好處就是可以用很少的索引數據,定位更多的數據,代價就是只能定位到索 引粒度的第一行,然后再進行進行一點掃描。
-
order by(必選)
order by 是 MergeTree 中唯一一個必填項,甚至比 primary key 還重要,因為當用戶不 設置主鍵的情況,很多處理會依照 order by 的字段進行處理
要求:主鍵必須是 order by 字段的前綴字段。
比如 order by 字段是 (id,sku_id) 那么主鍵必須是 id 或者(id,sku_id),主鍵不能是sku_id
-
二級索引
二級索引的功能在 v20.1.2.4 之前是被標注為實驗性的,之后版本默認是開啟的。
create table t_order_mt2( id UInt32, sku_id String, total_amount Decimal(16,2), create_time Datetime, INDEX a total_amount TYPE minmax GRANULARITY 5 #創建二級索引 ) engine =MergeTree partition by toYYYYMMDD(create_time) primary key (id) order by (id, sku_id);
-
數據 TTL
TTL 即 Time To Live,MergeTree 提供了可以管理數據表或者列的生命周期的功能。
TTL字段不能使用主鍵字段
-
列級別 TTL
create table t_order_mt3( id UInt32, sku_id String, total_amount Decimal(16,2) TTL create_time+interval 10 SECOND,#設置這個字段在createtime+10s后過期 create_time Datetime ) engine =MergeTree partition by toYYYYMMDD(create_time) primary key (id) order by (id, sku_id);
-
表級 TTL
alter table t_order_mt3 MODIFY TTL create_time + INTERVAL 10 SECOND;
涉及判斷的字段必須是 Date 或者 Datetime 類型,推薦使用分區的日期字段。
能夠使用的時間周期:
SECOND 、MINUTE、HOUR 、DAY 、 WEEK 、 MONTH 、 QUARTER 、 YEAR
-
-
-
ReplacingMergeTree
ReplacingMergeTree 是 MergeTree 的一個變種,它存儲特性完全繼承 MergeTree,多了一個去重的功能。
-
去重時機
數據的去重只會在合並的過程中出現。
-
去重范圍
如果表經過了分區,去重只會在分區內部進行去重,不能執行跨分區的去重。
➢ 實際上是使用 order by 字段作為唯一鍵
➢ 去重不能跨分區
➢ 只有同一批插入(新版本)或合並分區時才會進行去重
➢ 認定重復的數據保留,版本字段值最大的
➢ 如果版本字段相同則按插入順序保留最后一筆
-
-
SummingMergeTree
對於不查詢明細,只關心以維度進行匯總聚合結果的場景,提供了一種能夠“預聚合”的引擎 SummingMergeTree
➢ 以 SummingMergeTree()中指定的列作為匯總數據列
➢ 可以填寫多列必須數字列,如果不填,以所有非維度列且為數字列的字段為匯總數 據列
➢ 以 order by 的列為准,作為維度列
➢ 其他的列按插入順序保留第一行
➢ 不在一個分區的數據不會被聚合
➢ 只有在同一批次插入(新版本)或分片合並時才會進行聚合
第 5 章 SQL 操作
- Insert
基本與標准 SQL(MySQL)基本一致
- Update 和 Delete
這類操作被稱為 Mutation 查詢,它可以看 做 Alter 的一種。
雖然可以實現修改和刪除,但是和一般的 OLTP 數據庫不一樣,Mutation 語句是一種很 “重”的操作,而且不支持事務。
“重”的原因主要是每次修改或者刪除都會導致放棄目標數據的原有分區,重建新分區。 所以盡量做批量的變更,不要進行頻繁小數據的操作。
#刪除操作
alter table t_order_smt delete where sku_id ='sku_001';
#修改操作
alter table t_order_smt update total_amount=toDecimal32(2000.00,2) where id =102;
#由於操作比較“重”,所以 Mutation 語句分兩步執行,同步執行的部分其實只是進行新增數據新增分區和並把舊分區打上邏輯上的失效標記。直到觸發分區合並的時候,才會刪除舊數據釋放磁盤空間,一般不會開放這樣的功能給用戶,由管理員完成。
- 查詢操作
➢ 支持子查詢
➢ 支持 CTE(Common Table Expression 公用表表達式 with 子句)
➢ 支持各種 JOIN,但是 JOIN 操作無法使用緩存,所以即使是兩次相同的 JOIN 語句, ClickHouse 也會視為兩條新 SQL
➢ 窗口函數URL函數 | ClickHouse文檔
➢ 不支持自定義函數
➢ GROUP BY 操作增加了 with rollup\with cube\with total 用來計算小計和總計。
-
alter 操作
同 MySQL 的修改字段基本一致
1)新增字段
alter table tableName add column newcolname String after col1;
2)修改字段類型
alter table tableName modify column newcolname String;
3)刪除字段
alter table tableName drop column newcolname;
-
導出數據
Input and Output Formats | ClickHouse Documentation
clickhouse-client --query "select * from t_order_mt where create_time='2020-06-01 12:00:00'" --format CSVWithNames> /opt/module/data/rs1.csv
第 6 章 副本
三台服務器 clickhouse1、clickhouse2、clickhouse3
安裝zookeeper集群
- 副本寫入流程.
-
配置步驟
(1)啟動 zookeeper 集群
(2)在 clickhouse1的/etc/clickhouse-server/config.d目錄下創建一個名為 metric.xml(文件名自己指定,注意要將這個文件的權限設置成clickhouse) 的配置文件,內容如下:
也可以不創建外部文件,直接在 config.xml 中指定
<?xml version="1.0"?> <yandex> <!-- <zookeeper-servers> 按照教程,這里要寫上面的標簽,但是我寫成這個標簽下面創建表會報下面的錯誤, Code: 225. DB::Exception: Received from localhost:9000. DB::Exception: Can't create replicated table without ZooKeeper.--> <zookeeper><!--寫成這個是OK的--> <node index="1"> <host>clickhouse1</host> <port>2181</port> </node> <node index="2"> <host>clickhouse2</host> <port>2181</port> </node> <node index="3"> <host>clickhouse3</host> <port>2181</port> </node> <!--</zookeeper-servers>--> </zookeeper> </yandex>
(3)etc/clickhouse-server/config.xml 中增加
<!--查找zookeeper配置文件 進行增加配置--> <zookeeper incl="zookeeper-servers" optional="true" /> <include_from>/etc/clickhouse-server/config.d/metric.xml</include_from>
(4)同步上述兩個文件到 clickhouse2和 clickhouse3上
(5)重啟clickhouse集群
clickhouse restart
創建表
#clickhouse1上執行 create table t_order_rep2 ( id UInt32, sku_id String, total_amount Decimal(16,2), create_time Datetime ) engine =ReplicatedMergeTree('/clickhouse/table/01/t_order_rep','rep_102') partition by toYYYYMMDD(create_time) primary key (id) order by (id,sku_id);
#clickhouse2上執行 create table t_order_rep2 ( id UInt32, sku_id String, total_amount Decimal(16,2), create_time Datetime ) engine =ReplicatedMergeTree('/clickhouse/table/01/t_order_rep','rep_103') partition by toYYYYMMDD(create_time) primary key (id) order by (id,sku_id);
參數解釋
ReplicatedMergeTree 中,
第一個參數是分片的 zk_path 一般按照:/clickhouse/table/{shard}/{table_name} 的格式寫,如果只有一個分片就寫 01 即可。
第二個參數是副本名稱,相同的分片副本名稱不能相同。
第 7 章 分片集群
通過分片把一份完整的數據進行切 分,不同的分片分布到不同的節點上,再通過 Distributed 表引擎把數據拼接起來一同使用。
Distributed 表引擎本身不存儲數據,有點類似於 MyCat 之於 MySql,成為一種中間件, 通過分布式邏輯表來寫入、分發、路由來操作多台節點不同分片的分布式數據。
ClickHouse 的集群是表級別的,實際企業中,大部分做了高可用,但是沒有用分 片,避免降低查詢性能以及操作集群的復雜性。
- 集群寫入流程(3 分片 2 副本共 6 個節點)
-
集群讀取流程(3 分片 2 副本共 6 個節點)
-
配置步驟
-
集群及副本規划(2 個分片,只有第一個分片有副本)
-
配置步驟
在clickhouse1 服務器/etc/clickhouse-server/config.d 目錄下創建 metrika-shard.xml(修改文件所屬clickhouse用戶)文件
<?xml version="1.0"?>
<yandex>
<remote_servers>
<gmall_cluster> <!-- 集群名稱-->
<shard> <!--集群的第一個分片-->
<internal_replication>true</internal_replication>
<replica> <!--該分片的第一個副本-->
<host>clickhouse1</host>
<port>9000</port>
</replica>
<replica> <!--該分片的第二個副本-->
<host>clickhouse2</host>
<port>9000</port>
</replica>
</shard>
<shard> <!--集群的第二個分片-->
<internal_replication>true</internal_replication>
<replica> <!--該分片的第一個副本-->
<host>clickhouse3</host>
<port>9000</port>
</replica>
</shard>
</gmall_cluster>
</remote_servers>
<zookeeper>
<node index="1">
<host>clickhouse1</host>
<port>2181</port>
</node>
<node index="2">
<host>clickhouse2</host>
<port>2181</port>
</node>
<node index="3">
<host>clickhouse3</host>
<port>2181</port>
</node>
</zookeeper>
<macros>
<shard>01</shard> <!--不同機器放的分片數不一樣-->
<replica>rep_1_1</replica> <!--不同機器放的副本數不一樣-->
</macros>
</yandex>
-
修改/etc/clickhouse-server/config.xm
-
同步 config.xml、metrika-shard.xml到clickhouse2、clickhouse3,重啟
clickhouse restart
-
在clickhouse1上執行建表語句
➢ 會自動同步到集群中其他服務器
➢ 集群名字要和配置文件中的一致
➢ 分片和副本名稱從配置文件的宏定義中獲取
create table st_order_mt on cluster gmall_cluster ( id UInt32, sku_id String, total_amount Decimal(16,2), create_time Datetime ) engine =ReplicatedMergeTree('/clickhouse/tables/{shard}/st_order_mt','{replica}') partition by toYYYYMMDD(create_time) primary key (id) order by (id,sku_id);
-
在clickhouse1 上創建 Distribute 分布式表
create table st_order_mt_all2 on cluster gmall_cluster ( id UInt32, sku_id String, total_amount Decimal(16,2), create_time Datetime )engine = Distributed(gmall_cluster,default, st_order_mt,hiveHash(sku_id));
參數含義: Distributed(集群名稱,庫名,本地表名,分片鍵)
分片鍵必須是整型數字,所以用 hiveHash 函數轉換,也可以 rand()