Clickhouse 數據字典

運行環境:
Clickhouse 20.4.5.36
CentOS 7.6

數據字典概述:

數據字典是clickhouse提供的一種簡單 實用的存儲媒介,以鍵值和屬性映射的形式定義數據。字典中的數據會主動或被動加載到內存之中,並支持動態更新。由於字典數據常駐內存特特性,比較適合保存常量或者經常使用的維度表數據,以避免不必要的JOIN數據。

數據字典分爲內置和擴展兩種形式,內置數據字典是以clickhouse默認自帶的字典;外部字典是通過用戶自定義配置實現的字典。

在正常情況下字典中的數據只能通過字典函數訪問,但是也有例外,即特殊的字典表引擎。在字典表引擎的幫助下 可以將數據字典掛載到一張代理的數據表下,從而實現數據表和自帶數據的JOIN查詢。

 

Clickhouse是外部數據字典來處理多維數據架構,早期的clickhouse版本適用XML配置,在新版本中ClickHouse有了顯着的進步,字典也達到了新的實用水平。

########################### 數據字典 #######################
總覽
ClickHouse外部詞典是內存中的鍵值結構。它們可用於替換SQL中的聯接。在ClickHouse中支持多個表聯接之前,字典是
許多應用程序的靈丹妙藥(silver bullet)。
字典已插入外部資源。源可以是另一個數據庫(ClickHouse,MySQL或通用的ODBC),文件或Web服務中的表。 ClickHouse也
可以自動從外部來源刷新字典
以使其保持最新狀態。
以這種方式使用字典來處理ETL流程是過時的。由於字典通常是內存中的,因此它們可用於低頻率的查詢,以及通常可提高查詢性能。

但是數據字典存在兩個可用性問題。
首先,必須在XML配置文件中定義字典。無法使用DDL定義它們。這使模式管理變得不一致和不方便。
例如,如果沒有對物理服務器的訪問權限,則根本無法創建字典。

第二個問題是SQL兼容性。 BI工具和分析人員必須知道如何在SQL查詢中使用字典。人可以學習,但是BI工具不能。
因此,字典很難與Tableau等工具一起使用。



數據字典的DDL
在此之前需要創建大量的XML文件,在最新的ClickHouse 20.1版本中引入了CREATE DICTIONARY語句,至少需要20.1.11.73+版本:


CREATE DICTIONARY dict(
  key_column UInt64 DEFAULT 0,
  value_column String DEFAULT 'a'
)
PRIMARY KEY key_column
SOURCE(CLICKHOUSE(HOST 'localhost' PORT 9000 USER 'default' TABLE 't_dict' PASSWORD '' DB 'datasets'))
LIFETIME(MIN 1 MAX 10)
LAYOUT(HASHED());

我們使用DDL語句定義數據字典,我們可以使用如下語句查詢字典和查看字典的定義,當然也可以使用on cluster語法,將DDL語句傳播到集羣的每個節點。

Clickhouse> SHOW DICTIONARIES;

SHOW DICTIONARIES

┌─name─┐
│ dict │
└──────┘

1 rows in set. Elapsed: 0.003 sec. 

Clickhouse> SHOW CREATE DICTIONARY dict;

SHOW CREATE DICTIONARY dict

┌─statement──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ CREATE DICTIONARY datasets.dict
(
    `key_column` UInt64 DEFAULT 0, 
    `value_column` String DEFAULT 'a'
)
PRIMARY KEY key_column
SOURCE(CLICKHOUSE(HOST 'localhost' PORT 9000 USER 'default' TABLE 't_dict' PASSWORD '' DB 'datasets'))
LIFETIME(MIN 1 MAX 10)
LAYOUT(HASHED()) │
└────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘

1 rows in set. Elapsed: 0.001 sec. 
-- 測試函數 dictGet()

Clickhouse> select dictGet('datasets.dict','value_column',toUInt64(1));

SELECT dictGet('datasets.dict', 'value_column', toUInt64(1))

┌─dictGet('datasets.dict', 'value_column', toUInt64(1))─┐
│ A1                                                    │
└───────────────────────────────────────────────────────┘

1 rows in set. Elapsed: 2.541 sec. 

由於DDL字典是schema的一部分,需要在調用dictGet函數的時候加上數據字典的範圍。


使用字典JOIN
在2018年發佈了將可以將表的引擎設置爲Dictionary engine的功能,所以字典表可以被用於SQL查詢中,被當做表或者視圖。
這樣看起來更加智能,比起只存儲於內存之中,也可以獲得更加好的性能。

Clickhouse> select * from numbers(5) as n inner join dict on key_column=number;

SELECT *
FROM numbers(5) AS n
INNER JOIN dict ON key_column = number

┌─number─┬─key_column─┬─value_column─┐
│      0 │          0 │ A0           │
│      1 │          1 │ A1           │
│      2 │          2 │ A2           │
│      3 │          3 │ A3           │
│      4 │          4 │ A4           │
└────────┴────────────┴──────────────┘

5 rows in set. Elapsed: 0.017 sec. 
在早於20.3版本之前性能會比較差,需要耗費大量的時間。

Clickhouse> SELECT number,dictGet('datasets.dict', 'value_column', number) val FROM numbers(5);

SELECT 
    number, 
    dictGet('datasets.dict', 'value_column', number) AS val
FROM numbers(5)

┌─number─┬─val─┐
│      0 │ A0  │
│      1 │ A1  │
│      2 │ A2  │
│      3 │ A3  │
│      4 │ A4  │
└────────┴─────┘

5 rows in set. Elapsed: 0.011 sec. 

現在快了! 更改是微不足道的,但是它要求用戶知道某些表實際上是字典。 當然,許多用戶質疑ClickHouse爲什麼無法自動重寫查詢。 從最新的20.4版本開始,終於可以了!
在20.4版本之後:

Clickhouse> select * from numbers(5) as n inner join dict on key_column=number;

SELECT *
FROM numbers(5) AS n
INNER JOIN dict ON key_column = number

┌─number─┬─key_column─┬─value_column─┐
│      0 │          0 │ A0           │
│      1 │          1 │ A1           │
│      2 │          2 │ A2           │
│      3 │          3 │ A3           │
│      4 │          4 │ A4           │
└────────┴────────────┴──────────────┘

5 rows in set. Elapsed: 0.008 sec. 

Clickhouse> select version();

SELECT version()

┌─version()─┐
│ 20.4.5.36 │
└───────────┘

1 rows in set. Elapsed: 0.003 sec. 

SELECT 
    database, 
    name, 
    status, 
    origin, 
    type, 
    key, 
    attribute.names, 
    attribute.types, 
    query_count, 
    hit_rate, 
    element_count, 
    load_factor, 
    source, 
    loading_start_time, 
    loading_duration, 
    last_exception
FROM system.dictionaries

┌─database─┬─name─┬─status─┬─origin────────┬─type───┬─key────┬─attribute.names──┬─attribute.types─┬─query_count─┬─hit_rate─┬─element_count─┬────────load_factor─┬─source──────────────────────┬──loading_start_time─┬─loading_duration─┬─last_exception─┐
│ datasets │ dict │ LOADED │ datasets.dict │ Hashed │ UInt64 │ ['value_column'] │ ['String']      │           0 │        1 │      10000000 │ 0.2980232238769531 │ ClickHouse: datasets.t_dict │ 2020-06-27 20:33:37 │            1.845 │                │
└──────────┴──────┴────────┴───────────────┴────────┴────────┴──────────────────┴─────────────────┴─────────────┴──────────┴───────────────┴────────────────────┴─────────────────────────────┴─────────────────────┴──────────────────┴────────────────┘

1 rows in set. Elapsed: 0.012 sec.


可以看到使用JOIN 響應速度很快,實際上clickhouse不在需要JOIN 正確的表,他可以更加高效的進行字典調用。目前的版本只需要5次調用,而不需要掃描
1000萬行的表數據。
另外一個優點則是字典的所有屬性都可使用joinGet()函數join 到一起,這樣每個需要的屬性都可以自動的查詢到。

結論:
ClickHouse外部詞典最終成爲ClickHouse中的一等公民,詞典是模式的一部分,可以使用本地的DDL或者on cluster 方式創建。
從20.4版本開始,可以對用戶隱藏實現細節,由於clickhouse可以自動轉換join到字典的調用。
現在Clickhouse字典要比以前的版本更加用戶友好了。
DDL創建數據字典從19.17.4.11版本開始支持。

參考:

https://www.altinity.com/blog/2020/5/19/clickhouse-dictionaries-reloaded

https://www.altinity.com/blog/2017/4/20/clickhouse-dictionaries-benchmarking

https://www.altinity.com/blog/2017/4/12/dictionaries-explained

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章