Clickhouse表引擎之MergeTree

哥不是小蘿莉發表於2022-11-27

1.概述

在Clickhouse中有多種表引擎,不同的表引擎擁有不同的功能,它直接決定了資料如何讀寫、是否能夠併發讀寫、是否支援索引、資料是否可備份等等。本篇部落格筆者將為大家介紹Clickhouse中的各個表引擎以及其含義。

2.內容

2.1 MergeTree

適用於高負載任務的最通用和功能最強大的表引擎。這些引擎的共同特點是可以快速插入資料並進行後續的後臺資料處理。 MergeTree系列引擎支援資料複製(使用Replicated* 的引擎版本),分割槽和一些其他引擎不支援的其他功能。

Clickhouse 中最強大的表引擎當屬 MergeTree (合併樹)引擎及該系列(*MergeTree)中的其他引擎。MergeTree 系列的引擎被設計用於插入極大量的資料到一張表當中。資料可以以資料片段的形式一個接著一個的快速寫入,資料片段在後臺按照一定的規則進行合併。相比在插入時不斷修改(重寫)已儲存的資料,這種策略會高效很多。

主要特點:

  • 儲存的資料按主鍵排序,這使得您能夠建立一個小型的稀疏索引來加快資料檢索。
  • 如果指定了 分割槽鍵 的話,可以使用分割槽。在相同資料集和相同結果集的情況下 ClickHouse 中某些帶分割槽的操作會比普通操作更快。查詢中指定了分割槽鍵時 ClickHouse 會自動擷取分割槽資料。這也有效增加了查詢效能。
  • 支援資料副本。ReplicatedMergeTree 系列的表提供了資料副本功能。更多資訊,請參閱 資料副本 一節。
  • 支援資料取樣。需要的話,可以給表設定一個取樣方法。

其見表語句如下所示:

CREATE TABLE [IF NOT EXISTS] [db.]table_name [ON CLUSTER cluster]
(
    name1 [type1] [DEFAULT|MATERIALIZED|ALIAS expr1] [TTL expr1],
    name2 [type2] [DEFAULT|MATERIALIZED|ALIAS expr2] [TTL expr2],
    ...
    INDEX index_name1 expr1 TYPE type1(...) GRANULARITY value1,
    INDEX index_name2 expr2 TYPE type2(...) GRANULARITY value2
) ENGINE = MergeTree()
ORDER BY expr
[PARTITION BY expr]
[PRIMARY KEY expr]
[SAMPLE BY expr]
[TTL expr [DELETE|TO DISK 'xxx'|TO VOLUME 'xxx'], ...]
[SETTINGS name=value, ...]
  • ENGINE - 引擎名和引數。 ENGINE = MergeTree(). MergeTree 引擎沒有引數。
  • ORDER BY — 排序鍵。可以是一組列的元組或任意的表示式。 例如: ORDER BY (CounterID, EventDate) 。如果沒有使用 PRIMARY KEY 顯式指定的主鍵,ClickHouse 會使用排序鍵作為主鍵。如果不需要排序,可以使用 ORDER BY tuple()
  • PARTITION BY — 分割槽鍵 ,可選項。大多數情況下,不需要分使用區鍵。即使需要使用,也不需要使用比月更細粒度的分割槽鍵。分割槽不會加快查詢(這與 ORDER BY 表示式不同)。永遠也別使用過細粒度的分割槽鍵。不要使用客戶端指定分割槽識別符號或分割槽欄位名稱來對資料進行分割槽(而是將分割槽欄位標識或名稱作為 ORDER BY 表示式的第一列來指定分割槽)。要按月分割槽,可以使用表示式 toYYYYMM(date_column) ,這裡的 date_column 是一個 Date 型別的列。分割槽名的格式會是 "YYYYMM" 。
  • PRIMARY KEY - 如果要 選擇與排序鍵不同的主鍵,在這裡指定,可選項。預設情況下主鍵跟排序鍵(由 ORDER BY 子句指定)相同。 因此,大部分情況下不需要再專門指定一個 PRIMARY KEY 子句。
  • SAMPLE BY - 用於抽樣的表示式,可選項。如果要用抽樣表示式,主鍵中必須包含這個表示式。例如: SAMPLE BY intHash32(UserID) ORDER BY (CounterID, EventDate, intHash32(UserID)) 。
  • TTL - 指定行儲存的持續時間並定義資料片段在硬碟和捲上的移動邏輯的規則列表,可選項。表示式中必須存在至少一個 Date 或 DateTime 型別的列,比如:TTL date + INTERVAl 1 DAY規則的型別 DELETE|TO DISK 'xxx'|TO VOLUME 'xxx'指定了當滿足條件(到達指定時間)時所要執行的動作:移除過期的行,還是將資料片段(如果資料片段中的所有行都滿足表示式的話)移動到指定的磁碟(TO DISK 'xxx') 或 卷(TO VOLUME 'xxx')。預設的規則是移除(DELETE)。可以在列表中指定多個規則,但最多隻能有一個DELETE的規則。
  • SETTINGS — 控制 MergeTree 行為的額外引數,可選項:
    • index_granularity — 索引粒度。索引中相鄰的『標記』間的資料行數。預設值8192 。參考資料儲存。
    • index_granularity_bytes — 索引粒度,以位元組為單位,預設值: 10Mb。如果想要僅按資料行數限制索引粒度, 請設定為0(不建議)。
    • min_index_granularity_bytes - 允許的最小資料粒度,預設值:1024b。該選項用於防止誤操作,新增了一個非常低索引粒度的表。
    • enable_mixed_granularity_parts — 是否啟用透過 index_granularity_bytes 控制索引粒度的大小。在19.11版本之前, 只有 index_granularity 配置能夠用於限制索引粒度的大小。當從具有很大的行(幾十上百兆位元組)的表中查詢資料時候,index_granularity_bytes 配置能夠提升ClickHouse的效能。如果您的表裡有很大的行,可以開啟這項配置來提升SELECT 查詢的效能。
    • use_minimalistic_part_header_in_zookeeper — ZooKeeper中資料片段儲存方式 。如果use_minimalistic_part_header_in_zookeeper=1 ,ZooKeeper 會儲存更少的資料。更多資訊參考[服務配置引數](Server Settings | ClickHouse Documentation)這章中的 設定描述 。
    • min_merge_bytes_to_use_direct_io — 使用直接 I/O 來操作磁碟的合併操作時要求的最小資料量。合併資料片段時,ClickHouse 會計算要被合併的所有資料的總儲存空間。如果大小超過了 min_merge_bytes_to_use_direct_io 設定的位元組數,則 ClickHouse 將使用直接 I/O 介面(O_DIRECT 選項)對磁碟讀寫。如果設定 min_merge_bytes_to_use_direct_io = 0 ,則會禁用直接 I/O。預設值:10 * 1024 * 1024 * 1024 位元組。
    • merge_with_ttl_timeout — TTL合併頻率的最小間隔時間,單位:秒。預設值: 86400 (1 天)。
    • write_final_mark — 是否啟用在資料片段尾部寫入最終索引標記。預設值: 1(不要關閉)。
    • merge_max_block_size — 在塊中進行合併操作時的最大行數限制。預設值:8192
    • storage_policy — 儲存策略。 參見 使用具有多個塊的裝置進行資料儲存.
    • min_bytes_for_wide_part,min_rows_for_wide_part 在資料片段中可以使用Wide格式進行儲存的最小位元組數/行數。您可以不設定、只設定一個,或全都設定。
    • max_parts_in_total - 所有分割槽中最大塊的數量
    • max_compress_block_size - 在資料壓縮寫入表前,未壓縮資料塊的最大大小。您可以在全域性設定中設定該值(參見max_compress_block_size)。建表時指定該值會覆蓋全域性設定。
    • min_compress_block_size - 在資料壓縮寫入表前,未壓縮資料塊的最小大小。您可以在全域性設定中設定該值(參見min_compress_block_size)。建表時指定該值會覆蓋全域性設定。
    • max_partitions_to_read - 一次查詢中可訪問的分割槽最大數。

示例配置如下所示:

ENGINE MergeTree() PARTITION BY toYYYYMM(EventDate) ORDER BY (CounterID, EventDate, intHash32(UserID)) SAMPLE BY intHash32(UserID) SETTINGS index_granularity=8192

在這個例子中,我們設定了按月進行分割槽。同時我們設定了一個按使用者 ID 雜湊的抽樣表示式。這使得您可以對該表中每個 CounterID 和 EventDate 的資料偽隨機分佈。如果您在查詢時指定了 SAMPLE 子句。 ClickHouse會返回對於使用者子集的一個均勻的偽隨機資料取樣。index_granularity 可省略因為 8192 是預設設定 。

2.2 資料儲存

表由按主鍵排序的資料片段(DATA PART)組成。

當資料被插入到表中時,會建立多個資料片段並按主鍵的字典序排序。例如,主鍵是 (CounterID, Date) 時,片段中資料首先按 CounterID 排序,具有相同 CounterID 的部分按 Date 排序。

不同分割槽的資料會被分成不同的片段,ClickHouse 在後臺合併資料片段以便更高效儲存。不同分割槽的資料片段不會進行合併。合併機制並不保證具有相同主鍵的行全都合併到同一個資料片段中。

資料片段可以以 Wide 或 Compact 格式儲存。在 Wide 格式下,每一列都會在檔案系統中儲存為單獨的檔案,在 Compact 格式下所有列都儲存在一個檔案中。Compact 格式可以提高插入量少插入頻率頻繁時的效能。

資料儲存格式由 min_bytes_for_wide_part 和 min_rows_for_wide_part 表引擎引數控制。如果資料片段中的位元組數或行數少於相應的設定值,資料片段會以 Compact 格式儲存,否則會以 Wide 格式儲存。

每個資料片段被邏輯的分割成顆粒(granules)。顆粒是 ClickHouse 中進行資料查詢時的最小不可分割資料集。ClickHouse 不會對行或值進行拆分,所以每個顆粒總是包含整數個行。每個顆粒的第一行透過該行的主鍵值進行標記, ClickHouse 會為每個資料片段建立一個索引檔案來儲存這些標記。對於每列,無論它是否包含在主鍵當中,ClickHouse 都會儲存類似標記。這些標記讓您可以在列檔案中直接找到資料。

顆粒的大小透過表引擎引數 index_granularity 和 index_granularity_bytes 控制。顆粒的行數的在 [1, index_granularity] 範圍中,這取決於行的大小。如果單行的大小超過了 index_granularity_bytes 設定的值,那麼一個顆粒的大小會超過 index_granularity_bytes。在這種情況下,顆粒的大小等於該行的大小。

2.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 行額外的資料。

稀疏索引使得您可以處理極大量的行,因為大多數情況下,這些索引常駐於記憶體。

ClickHouse 不要求主鍵唯一,所以您可以插入多條具有相同主鍵的行。

2.4 主鍵的選擇

主鍵中列的數量並沒有明確的限制。依據資料結構,您可以在主鍵包含多些或少些列。這樣可以:

  • 改善索引的效能。
  • 如果當前主鍵是 (a, b) ,在下列情況下新增另一個 c 列會提升效能:
  • 查詢會使用 c 列作為條件
  • 很長的資料範圍( index_granularity 的數倍)裡 (a, b) 都是相同的值,並且這樣的情況很普遍。換言之,就是加入另一列後,可以讓您的查詢略過很長的資料範圍。
  • 改善資料壓縮。
  • ClickHouse 以主鍵排序片段資料,所以,資料的一致性越高,壓縮越好。
  • 在CollapsingMergeTree 和 SummingMergeTree 引擎裡進行資料合併時會提供額外的處理邏輯。

在這種情況下,指定與主鍵不同的 排序鍵 也是有意義的。

長的主鍵會對插入效能和記憶體消耗有負面影響,但主鍵中額外的列並不影響 SELECT 查詢的效能。

可以使用 ORDER BY tuple() 語法建立沒有主鍵的表。在這種情況下 ClickHouse 根據資料插入的順序儲存。如果在使用 INSERT ... SELECT 時希望保持資料的排序,請設定 max_insert_threads = 1。

2.5 選擇與排序鍵不同的主鍵

Clickhouse可以做到指定一個跟排序鍵不一樣的主鍵,此時排序鍵用於在資料片段中進行排序,主鍵用於在索引檔案中進行標記的寫入。這種情況下,主鍵表示式元組必須是排序鍵表示式元組的字首(即主鍵為(a,b),排序列必須為(a,b,**))。

當使用 SummingMergeTree 和 AggregatingMergeTree 引擎時,這個特性非常有用。通常在使用這類引擎時,表裡的列分兩種:維度 和 度量 。典型的查詢會透過任意的 GROUP BY 對度量列進行聚合並透過維度列進行過濾。由於 SummingMergeTree 和 AggregatingMergeTree 會對排序鍵相同的行進行聚合,所以把所有的維度放進排序鍵是很自然的做法。但這將導致排序鍵中包含大量的列,並且排序鍵會伴隨著新新增的維度不斷的更新。

在這種情況下合理的做法是,只保留少量的列在主鍵當中用於提升掃描效率,將維度列新增到排序鍵中。

對排序鍵進行 ALTER 是輕量級的操作,因為當一個新列同時被加入到表裡和排序鍵裡時,已存在的資料片段並不需要修改。由於舊的排序鍵是新排序鍵的字首,並且新新增的列中沒有資料,因此在表修改時的資料對於新舊的排序鍵來說都是有序的。

2.6 索引和分割槽在查詢中的應用

對於 SELECT 查詢,ClickHouse 分析是否可以使用索引。如果 WHERE/PREWHERE 子句具有下面這些表示式(作為完整WHERE條件的一部分或全部)則可以使用索引:進行相等/不相等的比較;對主鍵列或分割槽列進行IN運算、有固定字首的LIKE運算(如name like 'test%')、函式運算(部分函式適用),還有對上述表示式進行邏輯運算。

因此,在索引鍵的一個或多個區間上快速地執行查詢是可能的。下面例子中,指定標籤;指定標籤和日期範圍;指定標籤和日期;指定多個標籤和日期範圍等執行查詢,都會非常快。

當引擎配置如下時:

    ENGINE MergeTree() PARTITION BY toYYYYMM(EventDate) ORDER BY (CounterID, EventDate) SETTINGS index_granularity=8192

這種情況下,這些查詢:

SELECT count() FROM table WHERE EventDate = toDate(now()) AND CounterID = 34
SELECT count() FROM table WHERE EventDate = toDate(now()) AND (CounterID = 34 OR CounterID = 42)
SELECT count() FROM table WHERE ((EventDate >= toDate('2014-01-01') AND EventDate <= toDate('2014-01-31')) OR EventDate = toDate('2014-05-01')) AND CounterID IN (101500, 731962, 160656) AND (CounterID = 101500 OR EventDate != toDate('2014-05-01'))

ClickHouse 會依據主鍵索引剪掉不符合的資料,依據按月分割槽的分割槽鍵剪掉那些不包含符合資料的分割槽。

上文的查詢顯示,即使索引用於複雜表示式,因為讀表操作經過最佳化,所以使用索引不會比完整掃描慢。

下面這個例子中,不會使用索引。

SELECT count() FROM table WHERE CounterID = 34 OR URL LIKE '%upyachka%'

要檢查 ClickHouse 執行一個查詢時能否使用索引,可設定 force_index_by_date 和 force_primary_key 。

使用按月分割槽的分割槽列允許只讀取包含適當日期區間的資料塊,這種情況下,資料塊會包含很多天(最多整月)的資料。在塊中,資料按主鍵排序,主鍵第一列可能不包含日期。因此,僅使用日期而沒有用主鍵欄位作為條件的查詢將會導致需要讀取超過這個指定日期以外的資料。

2.7 部分單調主鍵的使用

考慮這樣的場景,比如一個月中的天數。它們在一個月的範圍內形成一個單調序列 ,但如果擴充套件到更大的時間範圍它們就不再單調了。這就是一個部分單調序列。如果使用者使用部分單調的主鍵建立表,ClickHouse同樣會建立一個稀疏索引。當使用者從這類表中查詢資料時,ClickHouse 會對查詢條件進行分析。如果使用者希望獲取兩個索引標記之間的資料並且這兩個標記在一個月以內,ClickHouse 可以在這種特殊情況下使用到索引,因為它可以計算出查詢引數與索引標記之間的距離。

如果查詢引數範圍內的主鍵不是單調序列,那麼 ClickHouse 無法使用索引。在這種情況下,ClickHouse 會進行全表掃描。

ClickHouse 在任何主鍵代表一個部分單調序列的情況下都會使用這個邏輯。

2.8 跳數索引

此索引在 CREATE 語句的列部分裡定義。

INDEX index_name expr TYPE type(...) GRANULARITY granularity_value

*MergeTree 系列的表可以指定跳數索引。 跳數索引是指資料片段按照粒度(建表時指定的index_granularity)分割成小塊後,將上述SQL的granularity_value數量的小塊組合成一個大的塊,對這些大塊寫入索引資訊,這樣有助於使用where篩選時跳過大量不必要的資料,減少SELECT需要讀取的資料量。

示例:

CREATE TABLE table_name
(
    u64 UInt64,
    i32 Int32,
    s String,
    ...
    INDEX a (u64 * i32, s) TYPE minmax GRANULARITY 3,
    INDEX b (u64 * length(s)) TYPE set(1000) GRANULARITY 4
) ENGINE = MergeTree()
...

上例中的索引能讓 ClickHouse 執行下面這些查詢時減少讀取資料量。

SELECT count() FROM table WHERE s < 'z'
SELECT count() FROM table WHERE u64 * i32 == 10 AND u64 * length(s) >= 1234

可用的索引型別

  • minmax 儲存指定表示式的極值(如果表示式是 tuple ,則儲存 tuple 中每個元素的極值),這些資訊用於跳過資料塊,類似主鍵。
  • set(max_rows) 儲存指定表示式的不重複值(不超過 max_rows 個,max_rows=0 則表示『無限制』)。這些資訊可用於檢查資料塊是否滿足 WHERE 條件。
  • ngrambf_v1(n, size_of_bloom_filter_in_bytes, number_of_hash_functions, random_seed) 儲存一個包含資料塊中所有 n元短語(ngram) 的 布隆過濾器 。只可用在字串上。 可用於最佳化 equals , like 和 in 表示式的效能。
    • n – 短語長度。
    • size_of_bloom_filter_in_bytes – 布隆過濾器大小,位元組為單位。(因為壓縮得好,可以指定比較大的值,如 256 或 512)。
    • number_of_hash_functions – 布隆過濾器中使用的雜湊函式的個數。
    • random_seed – 雜湊函式的隨機種子。
  • tokenbf_v1(size_of_bloom_filter_in_bytes, number_of_hash_functions, random_seed) 跟 ngrambf_v1 類似,但是儲存的是token而不是ngrams。Token是由非字母數字的符號分割的序列。
  • bloom_filter(bloom_filter([false_positive]) – 為指定的列儲存布隆過濾器

可選引數false_positive用來指定從布隆過濾器收到錯誤響應的機率。取值範圍是 (0,1),預設值:0.025

支援的資料型別:Int*, UInt*, Float*, Enum, Date, DateTime, String, FixedString, Array, LowCardinality, Nullable。

以下函式會用到這個索引: equals, notEquals, in, notIn, has

INDEX sample_index (u64 * length(s)) TYPE minmax GRANULARITY 4
INDEX sample_index2 (u64 * length(str), i32 + f64 * 100, date, str) TYPE set(100) GRANULARITY 4
INDEX sample_index3 (lower(str), str) TYPE ngrambf_v1(3, 256, 2, 0) GRANULARITY 4

函式支援
WHERE 子句中的條件可以包含對某列資料進行運算的函式表示式,如果列是索引的一部分,ClickHouse會在執行函式時嘗試使用索引。不同的函式對索引的支援是不同的。

set 索引會對所有函式生效,其他索引對函式的生效情況見下表:

函式 (運算子) / 索引 primary key minmax ngrambf_v1 tokenbf_v1 bloom_filter
equals (=, ==)
notEquals(!=, <>)
like
notLike
startsWith
endsWith
multiSearchAny
in
notIn
less (\<)
greater (>)
lessOrEquals (\<=)
greaterOrEquals (>=)
empty
notEmpty
hasToken

常量引數小於 ngram 大小的函式不能使用 ngrambf_v1 進行查詢最佳化。

需要注意的是,布隆過濾器可能會包含不符合條件的匹配,所以 ngrambf_v1, tokenbf_v1 和 bloom_filter 索引不能用於結果返回為假的函式,例如:

  • 可以用來最佳化的場景
    • s LIKE '%test%'
    • NOT s NOT LIKE '%test%'
    • s = 1
    • NOT s != 1
    • startsWith(s, 'test')
  • 不能用來最佳化的場景
    • NOT s LIKE '%test%'
    • s NOT LIKE '%test%'
    • NOT s = 1
    • s != 1
    • NOT startsWith(s, 'test')

2.9 併發資料訪問

對於表的併發訪問,我們使用多版本機制。換言之,當一張表同時被讀和更新時,資料從當前查詢到的一組片段中讀取。沒有冗長的的鎖。插入不會阻礙讀取。

對錶的讀操作是自動並行的。

2.10 列和表的 TTL

TTL用於設定值的生命週期,它既可以為整張表設定,也可以為每個列欄位單獨設定。表級別的 TTL 還會指定資料在磁碟和捲上自動轉移的邏輯。

TTL 表示式的計算結果必須是 日期 或 日期時間 型別的欄位。

示例:

TTL time_column
TTL time_column + interval

要定義interval, 需要使用 時間間隔 運算子。

TTL date_time + INTERVAL 1 MONTH
TTL date_time + INTERVAL 15 HOUR

2.10.1 列 TTL

當列中的值過期時, ClickHouse會將它們替換成該列資料型別的預設值。如果資料片段中列的所有值均已過期,則ClickHouse 會從檔案系統中的資料片段中刪除此列。

TTL子句不能被用於主鍵欄位。

示例:

建立表時指定 TTL,具體程式碼如下所示:

CREATE TABLE example_table
(
    d DateTime,
    a Int TTL d + INTERVAL 1 MONTH,
    b Int TTL d + INTERVAL 1 MONTH,
    c String
)
ENGINE = MergeTree
PARTITION BY toYYYYMM(d)
ORDER BY d;

為表中已存在的列欄位新增 TTL

ALTER TABLE example_table
    MODIFY COLUMN
    c String TTL d + INTERVAL 1 DAY;

修改列欄位的 TTL

ALTER TABLE example_table
    MODIFY COLUMN
    c String TTL d + INTERVAL 1 MONTH;

2.10.2 表 TTL

表可以設定一個用於移除過期行的表示式,以及多個用於在磁碟或捲上自動轉移資料片段的表示式。當表中的行過期時,ClickHouse 會刪除所有對應的行。對於資料片段的轉移特性,必須所有的行都滿足轉移條件。

TTL expr
    [DELETE|TO DISK 'xxx'|TO VOLUME 'xxx'][, DELETE|TO DISK 'aaa'|TO VOLUME 'bbb'] ...
    [WHERE conditions]
    [GROUP BY key_expr [SET v1 = aggr_func(v1) [, v2 = aggr_func(v2) ...]] ]

TTL 規則的型別緊跟在每個 TTL 表示式後面,它會影響滿足表示式時(到達指定時間時)應當執行的操作:

  • DELETE - 刪除過期的行(預設操作);
  • TO DISK 'aaa' - 將資料片段移動到磁碟 aaa;
  • TO VOLUME 'bbb' - 將資料片段移動到卷 bbb.
  • GROUP BY - 聚合過期的行

使用WHERE從句,您可以指定哪些過期的行會被刪除或聚合(不適用於移動)。GROUP BY表示式必須是表主鍵的字首。如果某列不是GROUP BY表示式的一部分,也沒有在SET從句顯示引用,結果行中相應列的值是隨機的(就好像使用了any函式)。

示例:

建立時指定 TTL

 

CREATE TABLE example_table
(
    d DateTime,
    a Int
)
ENGINE = MergeTree
PARTITION BY toYYYYMM(d)
ORDER BY d
TTL d + INTERVAL 1 MONTH [DELETE],
    d + INTERVAL 1 WEEK TO VOLUME 'aaa',
    d + INTERVAL 2 WEEK TO DISK 'bbb';

修改表的 TTL

ALTER TABLE example_table
    MODIFY TTL d + INTERVAL 1 DAY;

建立一張表,設定一個月後資料過期,這些過期的行中日期為星期一的刪除:

CREATE TABLE table_with_where
(
    d DateTime,
    a Int
)
ENGINE = MergeTree
PARTITION BY toYYYYMM(d)
ORDER BY d
TTL d + INTERVAL 1 MONTH DELETE WHERE toDayOfWeek(d) = 1;

建立一張表,設定過期的列會被聚合。列x包含每組行中的最大值,y為最小值,d為可能任意值。

CREATE TABLE table_for_aggregation
(
    d DateTime,
    k1 Int,
    k2 Int,
    x Int,
    y Int
)
ENGINE = MergeTree
ORDER BY (k1, k2)
TTL d + INTERVAL 1 MONTH GROUP BY k1, k2 SET x = max(x), y = min(y);

刪除資料

ClickHouse 在資料片段合併時會刪除掉過期的資料。

當ClickHouse發現資料過期時, 它將會執行一個計劃外的合併。要控制這類合併的頻率, 您可以設定 merge_with_ttl_timeout。如果該值被設定的太低, 它將引發大量計劃外的合併,這可能會消耗大量資源。

如果在兩次合併的時間間隔中執行 SELECT 查詢, 則可能會得到過期的資料。為了避免這種情況,可以在 SELECT 之前使用 OPTIMIZE 。

3.結束語

這篇部落格就和大家分享到這裡,如果大家在研究學習的過程當中有什麼問題,可以加群進行討論或傳送郵件給我,我會盡我所能為您解答,與君共勉!

另外,博主出書了《Kafka並不難學》和《Hadoop大資料探勘從入門到進階實戰》,喜歡的朋友或同學, 可以在公告欄那裡點選購買連結購買博主的書進行學習,在此感謝大家的支援。關注下面公眾號,根據提示,可免費獲取書籍的教學影片。

 

相關文章