ClickHouse是一個用於聯機分析(OLAP)的列式數據庫管理系統(DBMS)。git
OLAP(OnLine Analysis Processing ,聯機分析處理),核心思想就是創建多維度的數據立方體,以維度(Dimension)和度量(Measure)爲基本概念,輔以元數據,實現能夠鑽取、切片、切塊、旋轉等靈活、系統、直觀的數據展示。github
它的特徵有:算法
-數據以至關大的批次(> 1000行)更新,而不是單行更新;或者根本沒有更新。sql
MergeTree
是ClickHouse最經常使用的表引擎,支持主鍵索引,數據分區,數據副本和數據採樣等功能。數據庫
MergeTree寫入一批數據時,數據會以數據片斷的的形式寫入磁盤,而且數據片斷不可修改。爲了逼迫數據片斷過多,ClickHouse會經過後臺線程,按期合併這些數據片斷。緩存
CREATE TABLE [IF NOT EXISTS] [db_name].table_name (
)ENGINE = MergeTree()
[PARTITION BY expr]
[ORDER BY expr]
[PRIMARY KEY expr]
[SAMPLE BY expr]
[SETTINGS name=value,...]
複製代碼
(1)PARTITION BY
[選填]: 分區鍵,用於指定表數據以何種形式進行分區。分區鍵支持:單個列字段,元組的形式使用多個列字段,列表達式。不聲明的話,ClickHouse會生成一個all的分區。服務器
(2)ORDER BY
[必填]: 排序鍵,指定在一個數據片斷內,數據以何種標準排序。默認狀況下主鍵和排序鍵相同。markdown
(3)PRIMARY KEY
[選填]: 主鍵,主鍵字段生成一級索引,用於加上表查詢。MergeTree運行重複數據(ReplacingMergeTree能夠去重)多線程
(4) SAMPLE BY
[選填]: 抽樣表達式,聲明數據的採樣標準。聲明瞭此配置項,主鍵的配置也有聲明一樣的表達式。函數
ENGINE = MERGETREE()
ORDER BY (CounterID, EventDate, intHASH32(UserID))
SAMPLE BY intHASH32(UserID)
複製代碼
(5) SETTINGS
: index_granularity
表示索引的粒度,默認是8192。 MergeTree
在默認狀況下,每隔8192行數據才生產一條索引。
(1) partiton
: 分區目錄,數據以分區目錄的形式存放。
(2) columns.txt
:列信息文件
(3) count.txt
: 計數文件,記錄當前數據目錄下數據的總行數。
(4) primay.idx
: 一級索引文件,是稀疏索引,以二進制形式存儲。
(5) [Column].bin
: 數據文件,存儲某一列的數據,壓縮格式存儲,默認是LZ4壓縮格式。每一個列字段擁有獨立.bin文件。
(6) [Column].mrk
: 列字段標記文件,保存.bin中數據的偏移量信息。ClickHouse經過primay.idx
稀疏索引,找到對應數據的偏移量信息(.mrk),而後經過偏移量直接從.bin文件中讀取數據。
(7) [Column].mrk2
: 使用了自適應大小的索引間隔,標記文件會以.mrk2
命名。原理和.mrk
相同。
(8) partition.dat
和minmax_[Column].idx
:使用了分區鍵就會生成。partiton.dat
記錄當前分區下,分區表達式最終生成的值。minmax
索引記錄當前分區下分區字段對應原始數據的最大值和最小值。這樣方便查詢時,跳過沒必要要數據分區,減小須要掃描的範圍。
MergeTree的分區由分區ID決定,分區ID由分區鍵的取值決定。
(1)不指定分區鍵:默認分區爲all,全部數據都寫入這個分區。
(2)使用整型(兼容UInt64,包括有符號整型和無符號整型):若是沒法轉化成日期類型YYYYMMDD格式,按照該整型的字符串形式取值。
(3)使用日期類型:按照日期類型YYYYMMDD格式化後字符串輸出。
(4)其餘類型:分區鍵類型不屬於整型或者日期類型,例如Float64/String, 經過128Hash算法去Hash值做爲分區ID的取值。
MergeTree的特色在於分區的合併,從分區的命名能夠解讀其合併邏輯。命名規則:
PartitionID_MinBlockNum_MaxBlockNum_Level
複製代碼
完整的目錄合併過程
MergeTree的主鍵使用PRIMARY KEY定義,按照index_granularity間隔,爲數據表生成一級索引並保存至primary.idx文件,索引數據按照PRIMARY KEY排序。相比使用PRIMARY KEY,更常見的方式是經過ORDER BY指定主鍵。
MergeTree中,數據是按列存儲的,每一個列字段有對應的.bin文件。按列獨立存儲能夠更好地壓縮數據,最小化數據掃描的範圍。
壓縮數據塊的邏輯
數據標記和和索引區間是一一對齊的, 都按照index_granularity的間隔。
標記文件與.bin文件也一一對應,每個[Column].bin文件都有一個對應的[Column].mrk文件,記錄數據在.bin文件中的偏移量信息。
.mrk中每行數據,對應壓縮文件中偏移量和解壓縮文件中偏移量。
標記數據和一級索引數據不同,它不能常駐內存,使用LRU緩存策略替換。
MergeTree擁有主鍵,可是主鍵沒有惟一鍵的約束。ReplacingMergeTree
的處理邏輯
(1) 使用ORDER BY
排序鍵做爲判斷重複數據的惟一鍵。
(2) 只有在合併分區的時候纔會觸發刪除重複數據的邏輯
(3) 以數據分區爲單位刪除重複數據。當分區合併時,同一分區的重複數據被刪除,不一樣分區的合併數據不刪除。
(4) 數據去重時,分區內的數據已經基於ORDER BY
進行了排序,因此可以找到某些相鄰的重複數據。
(5) 數據去重的策略
在MergeTree
的每一個數據分區,數據按照order by
表達式排序,主鍵索引按照PRIMARY KEY
表達式取值並排序。通常狀況下,只須要定義ORDER BY
便可。
SummingMergeTree
和AggregatingMergeTree
的聚合都是根據order by
進行的。
若是同時聲明瞭ORDER BY
和PRIMARY KEY
, MergeTree
會強制要求PRIMARY KEY
字段必須是ORDER BY
的前綴。
處理邏輯:
(1) order by
排序鍵做爲聚合數據的條件Key
(2) 只有在合併分區的時候纔會觸發刪除重複數據的邏輯
(3) 以數據分區爲單位聚合數據。當分區合併時,同一分區的聚合key相同的數據會被合併彙總,而不一樣分區之間的數據不會被彙總。
(4) 定義引擎時,指定了columns彙總列,則sum彙總這些列字段;若是未指定,則聚合全部非主鍵的數值類型字段
(5) 彙總數據時,同一分區內,相同聚合key的多行數據合併成一行。其中,彙總字段進行sum計算,非彙總字段。使用第一行的數據。
(6) 以前嵌套結構,但列字段必需要Map後綴結尾。嵌套類型中,默認以第一個字段做爲聚合key。除第一個字段外,任何名稱以Key,Id,Type後綴結尾的字段,和第一個字段組成複合key。
沒有設置了ver版本號,保留同一組重複數據中的最後一行
設置了ver版本號,保留同一組重複數據中的ver取值最大的一行
AggregatingMergeTree
的order by
,``primary key同
SummingMergeTree`。
看下面例子
CREATE TABLE agg_table(
id String,
city String,
code AggregateFunction(uniq,String),
value AggregateFunction(sum,UInt32),
create_time DateTime,
)ENGINE = AggregatingMergeTree
PARTITIION BY toYYYYMM(create_time)
ORDER BY (id,city)
PRIMARY KEY id
複製代碼
其中,列字段id, city 是聚合條件,等同於
GROUP BY id,city
複製代碼
code,value是聚合字段,等同於
UNIQ(code), SUM(value)
複製代碼
AggregateFunction
是ClickHOuse一種特殊的數據類型,它可以以二進制的形式存儲中間狀態。寫入數據,須要調用*State
函數,讀取數據,須要調用 *Merge
函數
一般會使用MergeTree做爲底表,存儲全量的數據,而且新建一張物化視圖。
CREATE MATERIALIZED VIEW agg_view
ENGINE = AggregatingMergeTree()
PARTITION BY city
ORDER BY (id,city)
AS SELECT
id,
city,
uniqState(code) AS code,
sumState(value) AS value
FROM agg_table basic
GROUP BY id,city
複製代碼
對於ClickHouse這類高性能分析性數據庫而言,對數據源文件修改是代價高昂的操做。相對於修改源文件,會將修改和刪除轉換成新增操做,以增代刪。
CollapsingMergeTree
定義一個sign
標記位字段,記錄數據行的狀態。若是sign標記爲1,是一行有效的數據。sign標記爲-1,表示這行數據須要被刪除。
CREATE TABLE collpase_table(
id String,
code Int32,
create_time DateTime,
sign Int8
)ENGINE=CollapsingMergeTree(sign)
PARTITION BY toYYMM(create_time)
ORDER BY id
複製代碼
CollapsingMergeTree
一樣以order by判斷惟一性的依據。
(1)摺疊數據不是實時觸發的,和其餘MergeTree變種引擎同樣,這項特性在分區合併以後纔會體現。分區合併以前,用戶看到的是舊的數據。有2中方法解決:
查詢以前使用optimize TABLE table_name FINAL
強制分區合併,可是方法效率很低
改變查詢方式
SELECT id, sum(code), count(coude), avg(code), uniq(code)
FROM collpase_table
GROUP BY id
複製代碼
改爲
SELECT id, sum(code*sign), count(code*sign), avg(code*sign), uniq(code*sign)
FROM collpase_table
GROUP BY id
HAVING SUM(sign) >0
複製代碼
(2)只有相同分區內的數據才能被摺疊,
(3)CollapsingMergeTree
對寫入順序有着嚴格的要求。若是按照正常順序寫入,先寫入sign=1, 再寫入sign=-1,則可以正常摺疊。這種現象是CollapsingMergeTree
的處理機制引發的,它要求sign=1和sign=-1的數據相鄰,而分區內的數據基於order by排序,要實現sign=1和sign=-1的數據相鄰,須要按照順序寫入。
若是數據的寫入程序是單線程,能夠控制寫入順序;若是是多線程,可使用CollapsingMergeTree
rollup
按照聚合鍵從右向左上卷數據,基於聚合函數依次生成分組小計和總計。加上聚合鍵個數爲n, 最終會生成小計的個數是n+1。
SELECT table,name,sum(bytes_on_disk) FROM system.parts
GROUP BY table,name
WITH ROLLUP
ORDER BY table
複製代碼
最終的返回結果,附加了顯示名稱爲空的小計彙總行。
cube像立方體同樣,居於聚合鍵之間的全部組合生成小計信息。聚合鍵的個數爲n,最終小計組合的個數是2的n次方。
SELECT database,table,name,sum(bytes_on_disk) FROM
(
SELECT database,table,name,bytes_on_disk FROM system.parts WHERE table = 'hits_v1'
)
GROUP BY database,table,name
WITH CUBE
ORDER BY database,table,name
複製代碼
基於聚合函數對全部數據進行彙總
SELECT database,sum(bytes_on_disk),count(table) FROM system.parts
GROUP BY database
WITH TOTALS
複製代碼
個人公衆號:lyp分享的地方
個人知乎專欄: zhuanlan.zhihu.com/c_127546654…
個人博客:www.liangyaopei.com
Github Page: liangyaopei.github.io/