1.介紹
Clickhouse 中最強大的表引擎當屬 MergeTree (合並樹)引擎及該系列(MergeTree)中的其他引擎。MergeTree 允許依據主鍵和日期創建索引,並進行實時的數據更新操作。MergeTree 是 ClickHouse 里最為先進的表引擎。
請注意不要將 MergeTree 跟 Merge引擎混淆!!!
MergeTree 引擎系列的基本理念如下。當你有巨量數據要插入到表中,你要高效地一批批寫入數據片段,並希望這些數據片段在后台按照一定規則合並。相比在插入時不斷修改(重寫)數據進存儲,這種策略會高效很多。
主要特點:
存儲的數據按主鍵排序。
這讓你可以創建一個用於快速檢索數據的小稀疏索引。
允許使用分區,如果指定了分區鍵的話。
在相同數據集和相同結果集的情況下 ClickHouse 中某些帶分區的操作會比普通操作更快。查詢中指定了分區鍵時 ClickHouse 會自動截取分區數據。這也有效增加了查詢性能。
支持數據副本。
ReplicatedMergeTree 系列的表便是用於此。更多信息,請參閱官方文檔。
支持數據采樣。
需要的話,你可以給表設置一個采樣方法。
不使用采樣表達式的例子:
MergeTree(EventDate, (CounterID, EventDate), 8192)*
使用采樣表達式的例子:
MergeTree(EventDate, intHash32(UserID), (CounterID, EventDate, intHash32(UserID)), 8192)*
2. 建表
CREATE TABLE [IF NOT EXISTS] [db.]table_name [ON CLUSTER cluster] ( name1 [type1] [DEFAULT|MATERIALIZED|ALIAS expr1], name2 [type2] [DEFAULT|MATERIALIZED|ALIAS expr2], ... INDEX index_name1 expr1 TYPE type1(...) GRANULARITY value1, INDEX index_name2 expr2 TYPE type2(...) GRANULARITY value2 ) ENGINE = MergeTree() [PARTITION BY expr] [ORDER BY expr] [PRIMARY KEY expr] [SAMPLE BY expr] [SETTINGS name=value, ...]
MergeTree 引擎在創建時接收以下4個參數,
日期字段的名稱 (索引字段)
采樣表達式 (可選的)
含有主鍵相關字段的元組
稀疏索引的粒度(見下文)。
以 MergeTree 作為引擎的數據表必須含有一個獨立的 Date 字段。比如說, EventDate 字段。這個日期字段必須是 Date 類型的(非 DateTime 類型)。
主鍵可以是任意表達式構成的元組(通常是列名稱的元組),或者是單獨一個字段。
抽樣表達式(可選的)可以是任意表達式。這個表達式必須在主鍵中。上面的例子使用了 CounterID 的哈希 intHash32 作為采樣表達式,旨在近乎隨機地在 CounterID 和 EventDate 內打亂數據條目。換而言之,當我們在查詢中使用 SAMPLE 子句時,我們就可以得到一個近乎隨機分布的用戶列表。
數據表將數據分割為小的索引塊作為單位進行處理。 每個索引塊之間依照主鍵排序。每個索引塊記錄了指定的開始日期和結束日期。在您插入數據時,MergeTree 就會對數據進行排序處理,以保證存儲在索引塊內的數據有序。 索引塊之間的合並過程會在系統后台定期自動執行。MergeTree 引擎會選擇幾個相鄰的索引塊進行合並(通常是較小的索引塊), 然后對二者合並、排序。
具體而言, 向 MergeTree 表中插入數據時,引擎會首先對新數據執行遞增排序而保存索引塊;其后,數據索引塊之間又會進一步合並,以減少總體索引塊數量。 因此,合並過程本身並無過多排序工作。
3.主鍵和索引在查詢中的表現
我們以 (CounterID, Date) 以主鍵。排序好的索引的圖示會是下面這樣:
全部數據 : [-------------------------------------------------------------------------] CounterID: [aaaaaaaaaaaaaaaaaabbbbcdeeeeeeeeeeeeefgggggggghhhhhhhhhiiiiiiiiikllllllll] Date: [1111111222222233331233211111222222333211111112122222223111112223311122333] 標記: | | | | | | | | | | | a,1 a,2 a,3 b,3 e,2 e,3 g,1 h,2 i,1 i,3 l,3 標記號: 0 1 2 3 4 5 6 7 8 9 10
如果指定查詢如下:
CounterID in (‘a’,’h’),服務器會讀取標記號在 [0, 3) 和 [6, 8) 區間中的數據。
CounterID IN (‘a’,’h’) AND Date = 3,服務器會讀取標記號在 [1, 3) 和 [7, 8) 區間中的數據。
Date = 3,服務器會讀取標記號在 [1, 10] 區間中的數據。
上面例子可以看出使用索引通常會比全表描述要高效。
稀疏索引會引起額外的數據讀取。當讀取主鍵單個區間范圍的數據時,每個數據塊中最多會多讀 index_granularity * 2 行額外的數據。大部分情況下,當 index_granularity = 8192 時,ClickHouse的性能並不會降級。
稀疏索引讓你能操作有巨量行的表。因為這些索引是常駐內存(RAM)的。
ClickHouse 不要求主鍵惟一。所以,你可以插入多條具有相同主鍵的行。