ClickHouse(16)ClickHouse紀錄檔引擎Log詳細解析

2023-12-04 18:01:20

紀錄檔引擎系列

這些引擎是為了需要寫入許多小資料量(少於一百萬行)的表的場景而開發的。

這系列的引擎有:

  • StripeLog
  • Log
  • TinyLog

共同屬性

引擎:

  • 資料儲存在磁碟上。

  • 寫入時將資料追加在檔案末尾。

  • 不支援突變操作,也就是更新。

  • 不支援索引。

    這意味著 `SELECT` 在範圍查詢時效率不高。
    
  • 非原子地寫入資料。

    如果某些事情破壞了寫操作,例如伺服器的異常關閉,你將會得到一張包含了損壞資料的表。
    

差異

LogStripeLog 引擎支援:

  • 並行存取資料的鎖。

    `INSERT` 請求執行過程中表會被鎖定,並且其他的讀寫資料的請求都會等待直到鎖定被解除。如果沒有寫資料的請求,任意數量的讀請求都可以並行執行。
    
  • 並行讀取資料。

    在讀取資料時,ClickHouse 使用多執行緒。 每個執行緒處理不同的資料塊。
    

Log 引擎為表中的每一列使用不同的檔案。StripeLog 將所有的資料儲存在一個檔案中。因此 StripeLog 引擎在作業系統中使用更少的描述符,但是 Log 引擎提供更高的讀效能。

TinyLog 引擎是該系列中最簡單的引擎並且提供了最少的功能和最低的效能。TinyLog 引擎不支援並行讀取和並行資料存取,並將每一列儲存在不同的檔案中。它比其餘兩種支援並行讀取的引擎的讀取速度更慢,並且使用了和 Log 引擎同樣多的描述符。你可以在簡單的低負載的情景下使用它。

LogTinyLog 的不同之處在於,«標記» 的小檔案與列檔案存在一起。這些標記寫在每個資料塊上,並且包含偏移量,這些偏移量指示從哪裡開始讀取檔案以便跳過指定的行數。這使得可以在多個執行緒中讀取表資料。對於並行資料存取,可以同時執行讀取操作,而寫入操作則阻塞讀取和其它寫入。Log引擎不支援索引。同樣,如果寫入表失敗,則該表將被破壞,並且從該表讀取將返回錯誤。Log引擎適用於臨時資料,write-once 表以及測試或演示目的。

TinyLog

最簡單的表引擎,用於將資料儲存在磁碟上。每列都儲存在單獨的壓縮檔案中。寫入時,資料將附加到檔案末尾。

並行資料存取不受任何限制:

如果同時從表中讀取並在不同的查詢中寫入,則讀取操作將丟擲異常
如果同時寫入多個查詢中的表,則資料將被破壞。
這種表引擎的典型用法是 write-once:首先只寫入一次資料,然後根據需要多次讀取。查詢在單個流中執行。換句話說,此引擎適用於相對較小的表(建議最多1,000,000行)。如果您有許多小表,則使用此表引擎是適合的,因為它比Log引擎更簡單(需要開啟的檔案更少)。當您擁有大量小表時,可能會導致效能低下,但在可能已經在其它 DBMS 時使用過,則您可能會發現切換使用 TinyLog 型別的表更容易。不支援索引。

在 Yandex.Metrica 中,TinyLog 表用於小批次處理的中間資料。

stripelog

在你需要寫入許多小資料量(小於一百萬行)的表的場景下使用這個引擎。

建表

CREATE TABLE [IF NOT EXISTS] [db.]table_name [ON CLUSTER cluster]
(
    column1_name [type1] [DEFAULT|MATERIALIZED|ALIAS expr1],
    column2_name [type2] [DEFAULT|MATERIALIZED|ALIAS expr2],
    ...
) ENGINE = StripeLog

寫資料

StripeLog 引擎將所有列儲存在一個檔案中。對每一次 Insert 請求,ClickHouse 將資料塊追加在表檔案的末尾,逐列寫入。

ClickHouse 為每張表寫入以下檔案:

  • data.bin — 資料檔案。
  • index.mrk — 帶標記的檔案。標記包含了已插入的每個資料塊中每列的偏移量。

StripeLog 引擎不支援 ALTER UPDATEALTER DELETE 操作。

讀資料

帶標記的檔案使得 ClickHouse 可以並行的讀取資料。這意味著 SELECT 請求返回行的順序是不可預測的。使用 ORDER BY 子句對行進行排序。

使用範例

建表:

CREATE TABLE stripe_log_table
(
    timestamp DateTime,
    message_type String,
    message String
)
ENGINE = StripeLog

插入資料:

INSERT INTO stripe_log_table VALUES (now(),'REGULAR','The first regular message')
INSERT INTO stripe_log_table VALUES (now(),'REGULAR','The second regular message'),(now(),'WARNING','The first warning message')

我們使用兩次 INSERT 請求從而在 data.bin 檔案中建立兩個資料塊。

ClickHouse 在查詢資料時使用多執行緒。每個執行緒讀取單獨的資料塊並在完成後獨立的返回結果行。這樣的結果是,大多數情況下,輸出中塊的順序和輸入時相應塊的順序是不同的。例如:

SELECT * FROM stripe_log_table
┌───────────timestamp─┬─message_type─┬─message────────────────────┐
│ 2019-01-18 14:27:32 │ REGULAR      │ The second regular message │
│ 2019-01-18 14:34:53 │ WARNING      │ The first warning message  │
└─────────────────────┴──────────────┴────────────────────────────┘
┌───────────timestamp─┬─message_type─┬─message───────────────────┐
│ 2019-01-18 14:23:43 │ REGULAR      │ The first regular message │
└─────────────────────┴──────────────┴───────────────────────────┘

對結果排序(預設增序):

SELECT * FROM stripe_log_table ORDER BY timestamp
┌───────────timestamp─┬─message_type─┬─message────────────────────┐
│ 2019-01-18 14:23:43 │ REGULAR      │ The first regular message  │
│ 2019-01-18 14:27:32 │ REGULAR      │ The second regular message │
│ 2019-01-18 14:34:53 │ WARNING      │ The first warning message  │
└─────────────────────┴──────────────┴────────────────────────────┘

資料分享

ClickHouse經典中文檔案分享

參考文章