ClickHouse 架構概述之列(Columns)介紹


ClickHouse 架構概述之列(Columns)介紹

莫愁前路無知己,天下誰人不識君。

ClickHouse 是一個真正的列式數據庫管理系統(DBMS)。在 ClickHouse 中,數據始終是按列存儲的,包括矢量(向量或列塊)執行的過程。只要有可能,操作都是基於矢量進行分派的,而不是單個的值,這被稱為“矢量化查詢執行”,它有利於降低實際的數據處理開銷。

通常有兩種不同的加速查詢處理的方法:矢量化查詢執行和運行時代碼生成。在后者中,動態地為每一類查詢生成代碼,消除了間接分派和動態分派。這兩種方法中,並沒有哪一種嚴格地比另一種好。運行時代碼生成可以更好地將多個操作融合在一起,從而充分利用 CPU 執行單元和流水線。矢量化查詢執行不是特別實用,因為它涉及必須寫到緩存並讀回的臨時向量。如果 L2 緩存容納不下臨時數據,那么這將成為一個問題。但矢量化查詢執行更容易利用 CPU 的 SIMD 功能。ClickHouse 使用了矢量化查詢執行,同時初步提供了有限的運行時動態代碼生成。

列(Columns)

要表示內存中的列(實際上是列塊),需使用 IColumn 接口。該接口提供了用於實現各種關系操作符的輔助方法。幾乎所有的操作都是不可變的:這些操作不會更改原始列,但是會創建一個新的修改后的列。比如,IColumn::filter 方法接受過濾字節掩碼,用於 WHERE 和 HAVING 關系操作符中。另外的例子:IColumn::permute 方法支持 ORDER BY 實現,IColumn::cut 方法支持 LIMIT 實現等等。

IColumn::filter和IColumn::permute方法作為純虛函數,代碼位於dbms\src\Columns目錄下的IColumn.h中,在子類中有具體的實現,比如ColumnDecimal子類。

IColumn::cut方法在基類IColumn中實現,用於LIMIT操作。

不同的 IColumn 實現(ColumnUInt8ColumnString 等)負責不同的列內存布局。內存布局通常是一個連續的數組。對於數據類型為整型的列,只是一個連續的數組,比如 std::vector。對於 String 列和 Array 列,則由兩個向量組成:其中一個向量連續存儲所有的 String 或數組元素,另一個存儲每一個 String 或 Array 的起始元素在第一個向量中的偏移。而 ColumnConst 則僅在內存中存儲一個值,但是看起來像一個列。

對於ColumnString類,Chars用於存儲所有的String,offsets用於存儲每個String在Chars中的偏移。代碼位於dbms\src\Columns目錄下的ColumnString.h和ColumnString.cpp中。

對於ColumnArray類,data用於存儲數組元素,offsets用於存儲每個Array在data中的偏移,代碼位於dbms\src\Columns目錄下的ColumnArray.h和ColumnArray.cpp中。

 Column相關的代碼目錄位於dbms\src\Columns路徑下,涉及到的類及相互關系如下圖所示:

IColumn 具有用於數據的常見關系轉換的方法,但這些方法並不能夠滿足所有需求。比如,ColumnUInt64 沒有用於計算兩列和的方法,ColumnString 沒有用於進行子串搜索的方法。這些無法計算的例程在 Icolumn 之外實現。

列(Columns)上的各種函數可以通過使用 Icolumn 的方法來提取 Field 值,或根據特定的 Icolumn 實現的數據內存布局的知識,以一種通用但不高效的方式實現。為此,函數將會轉換為特定的 IColumn 類型並直接處理內部表示。比如,ColumnUInt64 具有 getData 方法,該方法返回一個指向列的內部數組的引用,然后一個單獨的例程可以直接讀寫或填充該數組。實際上,“抽象漏洞(leaky abstractions)”允許我們以更高效的方式來實現各種特定的例程。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM