【ClickHouse 技术系列】- ClickHouse 中的嵌套数据结构
簡介:本文翻譯自 Altinity 針對 ClickHouse 的系列技術文章。面向聯機分析處理(OLAP)的開源分析引擎 ClickHouse,因其優良的查詢性能,PB級的數據規模,簡單的架構,被國內外公司廣泛采用。本系列技術文章,將詳細展開介紹 ClickHouse。
前言
本文翻譯自 Altinity 針對 ClickHouse 的系列技術文章。面向聯機分析處理(OLAP)的開源分析引擎 ClickHouse,因其優良的查詢性能,PB 級的數據規模,簡單的架構,被國內外公司廣泛采用。
阿里云 EMR-OLAP 團隊,基于開源 ClickHouse 進行了系列優化,提供了開源 OLAP 分析引擎 ClickHouse 的云上托管服務。EMR ClickHouse 完全兼容開源版本的產品特性,同時提供集群快速部署、集群管理、擴容、縮容和監控告警等云上產品功能,并且在開源的基礎上優化了 ClickHouse 的讀寫性能,提升了 ClickHouse 與 EMR 其他組件快速集成的能力。訪問 ClickHouse - E-MapReduce - 阿里云 了解詳情。
譯者:何源(荊杭),阿里云計算平臺事業部高級產品專家
ClickHouse 中的嵌套數據結構
在這篇博客文章中,我們將了解 ClickHouse for MySQL 中的嵌套數據結構,以及如何將其與 PMM 結合使用來查看查詢。
嵌套結構在關系數據庫管理系統中并不常見。通常情況下,它只是平面表。有時,將非結構化信息存儲在結構化數據庫中會很方便。
我們正在努力將 ClickHouse 調整為用于 Percona 監控和管理 (PMM) 的長期存儲,尤其是存儲有關查詢的詳細信息。我們試圖解決的問題之一是,對導致特定查詢失敗的不同錯誤進行計數。
例如,對于日期為 2017-08-17 的查詢:
"SELECT foo FROM bar WHERE id=?"被執行了 1000 次。其中 25 次失敗的錯誤代碼為“1212”,8 次失敗的錯誤代碼為“1250”。當然,在關系數據中進行存儲的傳統方法是創建一個表 "Date, QueryID, ErrorCode, ErrorCnt",然后對這個表執行 JOIN。遺憾的是,列式數據庫在多個 Join 的情況下表現不佳,通常建議使用非規范化表。
我們可以為每個可能的 ErrorCode 創建一個列,但這并不是最優解。可能有成千上萬的列,而且大多數時候它們都是空的。
在這種情況下,ClickHouse 提出了嵌套數據結構。對于我們的情況,這些可以定義為:
CREATE TABLE queries (Period Date,QueryID UInt32,Fingerprint String,Errors Nested(ErrorCode String,ErrorCnt UInt32) )Engine=MergeTree(Period,QueryID,8192);這個解決方案有明顯的問題:我們如何在這個表中插入數據?我們如何提取它?
我們先從 INSERT 開始。插入可能如下所示:
INSERT INTO queries VALUES ('2017-08-17',5,'SELECT foo FROM bar WHERE id=?',['1220','1230','1212'],[5,6,2])這意味著 2017-08-17 期間插入的查詢出現了 5 次錯誤 1220,6 次錯誤 1230,2 次錯誤 1212。
那么在不同的日期,它可能會產生不同的錯誤:
INSERT INTO queries VALUES ('2017-08-18',5,'SELECT foo FROM bar WHERE id=?',['1220','1240','1258'],[3,2,1])讓我們看一下 SELECT 數據的方法。非常基礎的 SELECT:
SELECT * FROM queries |_____Period_|_QueryID_|_Fingerprint_|_Errors.ErrorCode_______|_Errors.ErrorCnt_| | 2017-08-17 | 5 | SELECT foo | ['1220','1230','1212'] | [5,6,2] | | 2017-08-18 | 5 | SELECT foo | ['1220','1240','1260'] | [3,16,12] | |____________|_________|_____________|________________________|_________________|如果我們想使用更熟悉的表格輸出,則可以使用 ARRAY JOIN 擴展:
SELECT * FROM queries ARRAY JOIN Errors ┌─────Period─┬─QueryID─┬─Fingerprint─┬─Errors.ErrorCode─┬─Errors.ErrorCnt─┐ │ 2017-08-17 │ 5 │ SELECT foo │ 1220 │ 5 │ │ 2017-08-17 │ 5 │ SELECT foo │ 1230 │ 6 │ │ 2017-08-17 │ 5 │ SELECT foo │ 1212 │ 2 │ │ 2017-08-18 │ 5 │ SELECT foo │ 1220 │ 3 │ │ 2017-08-18 │ 5 │ SELECT foo │ 1240 │ 16 │ │ 2017-08-18 │ 5 │ SELECT foo │ 1260 │ 12 │ └────────────┴─────────┴─────────────┴──────────────────┴─────────────────┘但是,通常我們希望看到多個期間的聚合,這可以通過傳統的聚合函數來完成:
SELECT QueryID,Errors.ErrorCode,SUM(Errors.ErrorCnt) FROM queries ARRAY JOIN Errors GROUP BY QueryID,Errors.ErrorCode ┌─QueryID─┬─Errors.ErrorCode─┬─SUM(Errors.ErrorCnt)─┐ │ 5 │ 1212 │ 2 │ │ 5 │ 1230 │ 6 │ │ 5 │ 1260 │ 12 │ │ 5 │ 1240 │ 16 │ │ 5 │ 1220 │ 8 │ └─────────┴──────────────────┴──────────────────────┘如果我們別出心裁,每個 QueryID 只返回一行,我們也可以這么做:
SELECT QueryID, groupArray((ecode, cnt)) FROM (SELECT QueryID, ecode, sum(ecnt) AS cntFROM queries ARRAY JOIN Errors.ErrorCode AS ecode, Errors.ErrorCnt AS ecntGROUP BY QueryID, ecode ) GROUP BY QueryID ┌─QueryID─┬─groupArray(tuple(ecode, cnt))──────────────────────────────┐ │ 5 │ [('1230',6),('1212',2),('1260',12),('1220',8),('1240',16)] │ └─────────┴────────────────────────────────────────────────────────────┘結論
ClickHouse 提供了靈活的方式來存儲數據,盡管它是一個列式數據庫,但可以實現較低的結構化程度,并提供各種函數來提取和聚合數據。
后續
您已經了解了在 ClickHouse 中處理實時更新相關內容,本系列還包括其他內容:
- 在 ClickHouse 中處理實時更新
- 使用新的 TTL move,將數據存儲在合適的地方
- 在 ClickHouse 物化視圖中使用 Join
- ClickHouse 聚合函數和聚合狀態
- ClickHouse 中的嵌套數據結構(本文)
原文鏈接
本文為阿里云原創內容,未經允許不得轉載。?
總結
以上是生活随笔為你收集整理的【ClickHouse 技术系列】- ClickHouse 中的嵌套数据结构的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Jaeger插件开发及背后的思考
- 下一篇: 干掉讨厌的 CPU 限流,让容器跑得更快