ClickHouse為什么查詢速度快?
一、從存儲引擎視角看
ClickHouse速度快的秘訣在于——利用存儲引擎的特殊設計充分減少磁盤I/O對查詢速度的影響。從用戶提交一條SQL語句進行查詢到最終輸出結果的過程中,大量的時間是消耗在了磁盤I/O上,在很多情況下,I/O所占用的時間可以達到整個時間的90%以上。對存儲引擎磁盤I/O的優化可以獲得非常大的收益。ClickHouse的存儲引擎設計中大量優化的目的也是為了減少磁盤I/O。本節將從該視角對ClickHouse存儲引擎的優化進行解讀。
1、預排序
ClickHouse與傳統事務數據庫的一個不同之處在于ClickHouse寫入數據文件的數據時有序的,這就是本節將要介紹的預排序:將數據在寫入磁盤前進行排序,以保證數據在磁盤上有序。
預排序在數據庫系統是一個被廣泛使用的技術,在實現范圍查找時,可以將大量的隨機讀轉換為順序讀,從而有效提高I/O效率,降低范圍查詢時的I/O時間。在點查找時,預排序能做到和未排序數據相同的性能。因此,預排序可以在不降低點查找性能的情況下,有效提高范圍查詢的性能。
2、列存
列存數據庫和行存數據庫最根本的區別在于列存數據庫將一行數據拆分到多個數據文件中。在列存數據庫中,同一列的所有數據都在同一個文件中,因此在硬盤上是連續的。這種特性特別適合OLAP的低范式查詢場景。
3、壓縮
ClickHouse的另一個降低I/O的手段是壓縮,壓縮可以減少讀取和寫入的數據量,從而減少I/O時間。并不是所有場景下都可以引入壓縮的,很顯然,壓縮必然帶來壓縮和解壓縮的CPU消耗,這是一個利用CPU時間換I/O時間的手段。事務數據庫由于大部分情況下是針對行的操作,因此如果對每一行都進行一次壓縮解壓縮,帶來的時間消耗是遠大于磁盤I/O時間的。這就是事務數據庫沒有使用壓縮技術的原因。
而ClickHouse則不同,ClickHouse的最小處理單元是塊,塊一般由8192行數據組成,ClickHouse的一次壓縮針對的是8192行數據,這就極大降低CPU的壓縮和解壓縮時間。同時,ClickHouse是列存數據庫,同一列的數據相對更有規律,因此能夠帶來比較大的壓縮比。因此,塊+壓縮在ClickHouse中成為一個非常關鍵的優化手段。
二、從計算引擎視角看
不同于存儲引擎的設計,ClickHouse計算引擎的設計在很多方面都有著很大的爭議,一方面向量化引擎的精妙設計讓人拍案叫絕,另一方面相對粗糙的SQL解析和優化(解釋)器也讓ClickHouse在執行某些操作時讓用戶咬牙切齒。
1、 ClickHouse速度快的前提
在正式進入本節內容之前,我們首先需要明確一個前提:ClickHous不是在所有場景下都能獲得很強的性能。因此,需要先分析ClickHouse在滿足哪些前提下才能獲得最強的查詢性能。
ClickHouse計算引擎最精妙的設計在于向量化引擎,那么ClickHouse由于計算引擎原因導致的快,肯定是來自向量化引擎的加持。而ClickHouse的計算引擎導致的慢是因為缺乏代價優化器,那么由于計算引擎導致的慢也來自缺乏代價優化器帶來的缺陷?;谶@兩個邏輯,我們可以分析出ClickHouse速度快的前提。
1)大量使用向量化運算
ClickHouse提供了很多內置函數,在使用這些內置函數時,ClickHouse會自動進行向量化優化。因此盡可能使用提供的內置函數進行計算,而不是自己寫SQL語句。下面展示錯誤的SQL寫法以及正確的寫法。
2)查詢語句中沒有使用Join子句,或盡可能少的使用Join操作
ClickHouse沒有代價優化器,這導致了ClickHouse在Join操作時會出現內存不足等情況,導致查詢失敗。Join的性能問題其實并不僅僅是ClickHouse才遇到,任何數據庫在遇到大表Join時都有可能導致查詢時間暴增。
大數據中的Spark計算引擎對Join操作做了非常多的優化,借助其強大的CBO實現了Join算法的自動選擇。更是在此基礎上,通過AQE(Adaptive Query Execution,自適應查詢引擎),解決了大表Join操作時遇到數據傾斜時的性能問題。
正是由于ClickHouse沒有實現CBO,因此ClickHouse在實現Join操作時,選擇余地很少。尤其是分布式大表Join操作時,ClickHouse只實現了廣播連接(Broadcast Join)算法,極大地降低了ClickHouse的Join能力。
在使用ClickHouse時,應當盡可能避免Join操作。而Join操作在ODS建模的過程中大量存在。因此,ClickHouse在設計良好的DW上運行向量化查詢的性能最高。讀者應該盡可能避免將ClickHouse用于ODS的建模工作中。當數據量大時,這類建模工作還是盡可能下推到Spark上執行。
2、ClickHouse快的本質
ClickHouse在滿足上面提到的兩個條件時,在不考慮存儲引擎影響的情況下,應當能夠在計算引擎上達到最大的性能。ClickHouse計算引擎快的本質是利用了CPU提供的硬件加速特性。
除此之外,ClickHouse客觀上的確在一些環節存在著一些問題,個人認為這些問題和ClickHouse的定位有關。ClickHouse在設計之初就給自身進行了清晰的定位——充分發揮單機性能的OLAP引擎。在此基礎上,分布式的join能力其實并不重要,畢竟業界已經有Spark了,完全可以將ClickHouse建立在Spark之上,由Spark解決建模問題,由ClickHouse強大的DW分析能力實現OLAP的最后一公里問題。
作為用戶,我們應該清晰地了解ClickHouse速度快的前提,有意識地避開ClickHouse的雷區,不要將ClickHouse用于其不擅長的場景。正如此時此刻,大家都意識到了MySQL無法解決大數據量的OLAP問題,這類問題要通過專業的OLAP引擎解決。
開源社區要的并不是什么能力都有的但都不強的平庸的軟件,而是百花齊放,各自有著各自擅長的領域,通過組合實現架構上的合力。以上僅代表作者個人觀點,歡迎讀者有不同意見,大家互相討論。
三、總結
本文分別對ClickHouse的存儲引擎和計算引擎進行了簡單分析,分別得出了ClickHouse速度快的不同的前提。
存儲引擎需求的前提如下。
- 使用MergeTree存儲引擎。
- 按照業務需求,正確設置數據表的排序鍵,查詢時需滿足最左原則。
計算引擎架構要求的前提如下。
- 沒有或少用Join操作。
- 盡可能多地使用內置函數。
當滿足如上4個條件時,使用ClickHouse才有可能達到比較優秀的性能。關于作者:陳峰,資深大數據專家和架構師,ClickHouse技術專家,滴普科技(2B領域獨角獸)合伙人兼首席架構師。《ClickHouse性能之巔:從架構設計解讀性能之謎》作者。?