1. ClickHouse設(shè)計(jì)思想和核心技術(shù)特征
1.1 ClickHouse 全知全解
ClickHouse 是一個(gè)用于聯(lián)機(jī)分析 (OLAP) 的列式數(shù)據(jù)庫(kù)管理系統(tǒng) (DBMS)坎匿。來(lái)自于 2011 年在納斯達(dá)克上市的俄羅斯本土搜索引擎企業(yè) Yandex 公司盾剩, 誕生之初就是為了服務(wù) Yandex 公司自家的 Web 流量分析產(chǎn)品 Yandex.Metrica,后來(lái)經(jīng)過(guò)演變替蔬,逐漸形成為現(xiàn)在的 ClickHouse告私,全稱是:Click Stream, Data WareHouse
ClickHouse 官網(wǎng):https://clickhouse.tech/,它具有 ROLAP承桥、在線實(shí)時(shí)查詢驻粟、完整的 DBMS 功能支持、列式存儲(chǔ)凶异、不需要任何數(shù)據(jù)預(yù)處理蜀撑、支持批量更 新、擁有非常完善的 SQL 支持和函數(shù)剩彬、支持高可用酷麦、不依賴 Hadoop 復(fù)雜生態(tài)、開箱即用等許多特點(diǎn)喉恋。
在 1 億數(shù)據(jù)集體量的情況下沃饶,ClickHouse 的平均響應(yīng)速度是 Vertica 的 2.63 倍、InfiniDB 的 17 倍轻黑、MonetDB 的 27 倍糊肤、Hive 的 126 倍、MySQL 的 429 倍以及Greenplum 的 10 倍苔悦。詳細(xì)的測(cè)試結(jié)果可以查閱:https://clickhouse.tech/benchmark/dbms/轩褐。
ClickHouse 非常適用于商業(yè)智能領(lǐng)域(也就是我們所說(shuō)的 BI 領(lǐng)域),除此之外玖详,它也能夠被廣泛應(yīng)用于廣告流量把介、Web勤讽、App 流量、電信拗踢、金融脚牍、電子 商務(wù)、信息安全巢墅、網(wǎng)絡(luò)游戲诸狭、物聯(lián)網(wǎng)等眾多其他領(lǐng)域。
ClickHouse 是近年來(lái)備受關(guān)注的開源列式數(shù)據(jù)庫(kù)君纫,主要用于數(shù)據(jù)分析(OLAP)領(lǐng)域驯遇。目前國(guó)內(nèi)社區(qū)火熱,各個(gè)大廠紛紛跟進(jìn)大規(guī)模使用:
- 今日頭條內(nèi)部用 ClickHouse 來(lái)做用戶行為分析蓄髓,內(nèi)部一共幾千個(gè) ClickHouse 節(jié)點(diǎn)叉庐,單集群最大 1200 節(jié)點(diǎn),總數(shù)據(jù)量幾十 PB会喝,日增原始數(shù)據(jù) 300TB 左右陡叠。
- 騰訊內(nèi)部用 ClickHouse 做游戲數(shù)據(jù)分析,并且為之建立了一整套監(jiān)控運(yùn)維體系肢执。
- 攜程內(nèi)部從 18 年 7 月份開始接入試用枉阵,目前 80% 的業(yè)務(wù)都跑在 ClickHouse 上。每天數(shù)據(jù)增量十多億预茄,近百萬(wàn)次查詢請(qǐng)求兴溜。
- 快手內(nèi)部也在使用 ClickHouse,存儲(chǔ)總量大約 10PB反璃, 每天新增 200TB昵慌, 90% 查詢小于 3S。
ClickHouse 缺點(diǎn):
- 沒有完整的事務(wù)支持;
- 稀疏索引導(dǎo)致 ClickHouse 不擅長(zhǎng)細(xì)粒度或者 key-value 類型數(shù)據(jù)的查詢需求;
- 缺少高頻率淮蜈,低延遲的修改或刪除已存在數(shù)據(jù)的能力。僅能用于批量刪除或修改數(shù)據(jù) ;
- 不擅長(zhǎng) join 操作;
1.2 ClickHouse 設(shè)計(jì)思路剖析
那么一個(gè)專門用來(lái)做 OLAP 分析的存儲(chǔ)引擎該如何設(shè)計(jì)呢?
如何在海量數(shù)據(jù)中已卷,針對(duì)大量數(shù)據(jù)進(jìn)行查詢分析呢?核心需求是 實(shí)現(xiàn)海量數(shù)據(jù)集中的高性能低延遲查詢分析功能梧田,一些常見的方案和手段如下:
- 數(shù)據(jù)排序
- 數(shù)據(jù)分區(qū)分片 + 分布式查詢
- 列式存儲(chǔ) + 字段類型統(tǒng)一
- 列裁剪
- 預(yù)聚合(搜索引擎: 輸入關(guān)鍵詞,搜索引擎根據(jù)關(guān)鍵詞到 數(shù)據(jù)庫(kù) 找到這個(gè) 關(guān)鍵詞對(duì)應(yīng)的所有的 URL:這些 URL 就是提前計(jì)算出來(lái)的 )
- 利用CPU特性:向量化引擎侧蘸,操作系統(tǒng)必須支持;
- 主鍵索引 + 二級(jí)索引 + 位圖索引 + 布隆索引 等等各種索引技術(shù)
- 支持近似計(jì)算, pv 一個(gè)電商平臺(tái)的 sku 總數(shù);
- 定制引擎:多樣化的存儲(chǔ)引擎滿足不同場(chǎng)景的特定需要;
- 多樣化算法選擇:Volnitsky高效字符串搜索算法 和 HyperLogLog基于概率高效去重算法;
總結(jié)一下:?jiǎn)螚l記錄的增刪改查操作裁眯,通過(guò)數(shù)據(jù)橫向切割,做到數(shù)據(jù)操作的快速定位讳癌,在海量數(shù)據(jù)分析中穿稳,一般就是針對(duì)大量行數(shù)據(jù)少列做分析,既然并不是全部列晌坤,那么把數(shù)據(jù)做縱向切分把表中的數(shù)據(jù)按照列來(lái)單獨(dú)存儲(chǔ)逢艘,那么在做分析的時(shí)候旦袋,同樣可以快速把待查詢分析的數(shù)據(jù)總量降低到原來(lái)表的 1/n,同樣提高效率它改。而且對(duì)于常用的聚合邏輯的結(jié)果疤孕,也可以提前算出來(lái)緩存起來(lái)用來(lái)提供效率,這就是預(yù)聚合技術(shù)央拖。
提到預(yù)聚合祭阀,大家會(huì)想到 Kylin, Kylin 是一個(gè)把預(yù)聚合技術(shù)發(fā)揮到極致的一個(gè) OLAP 技術(shù)鲜戒,但是 Kylin 也有它的缺點(diǎn):
- 預(yù)聚合只支持固定的分析場(chǎng)景专控,無(wú)法滿足自定義分析場(chǎng)景,所以預(yù)聚合只能作為一種可選方案 ;
- 維度組合爆炸會(huì)導(dǎo)致數(shù)據(jù)膨脹遏餐,這樣會(huì)造成不必要的計(jì)算和存儲(chǔ)開銷踩官。無(wú)必要的維度組合的計(jì)算就屬于浪費(fèi)資源 ;
- 大概率數(shù)據(jù)都是增量生成,預(yù)聚合不能進(jìn)行數(shù)據(jù)更新境输。所以會(huì)產(chǎn)生大量的重算蔗牡。
2 ClickHouse 引擎詳解
ClickHouse 是一個(gè) OLAP 類型的分析型數(shù)據(jù)庫(kù),也有庫(kù)和表的概念嗅剖,而且?guī)旌捅磉€都提供了不同類型的引擎辩越。所以關(guān)于 ClickHouse 的底層引擎,其實(shí)可以分為 數(shù)據(jù)庫(kù)引擎 和 表引擎 兩種信粮。在此黔攒,我們重點(diǎn)講解表引擎。
2.1 ClickHouse 庫(kù)引擎介紹
關(guān)于庫(kù)引擎强缘,簡(jiǎn)單總結(jié)一下督惰。ClickHouse 也支持在創(chuàng)建庫(kù)的時(shí)候,指定庫(kù)引擎旅掂,目前支持 5 種赏胚,分別是:Ordinary,Dictionary商虐, Memory觉阅, Lazy, MySQL秘车,其實(shí) Ordinary 是默認(rèn)庫(kù)引擎典勇,在此類型庫(kù)引擎下,可以使用任意類型的表引擎叮趴。
Ordinary引擎: 默認(rèn)引擎割笙,如果不指定數(shù)據(jù)庫(kù)引擎創(chuàng)建的就是 Ordinary 數(shù)據(jù)庫(kù);
Dictionary引擎: 此數(shù)據(jù)庫(kù)會(huì)自動(dòng)為所有數(shù)據(jù)字典創(chuàng)建表 ;
Memory引擎: 所有數(shù)據(jù)只會(huì)保存在內(nèi)存中,服務(wù)重啟數(shù)據(jù)消失眯亦,該數(shù)據(jù)庫(kù)引擎只能夠創(chuàng)建 Memory 引擎表 ;
MySQL引擎: 改引擎會(huì)自動(dòng)拉取遠(yuǎn)端 MySQL 中的數(shù)據(jù)伤溉,并在該庫(kù)下創(chuàng)建 MySQL 表引擎的數(shù)據(jù)表;
Lazy延時(shí)引擎: 在距最近一次訪問間隔 expiration_time_in_seconds 時(shí)間段內(nèi)般码,將表保存在內(nèi)存中,僅適用于 Log 引擎表;
2.2 ClickHouse 表引擎介紹
表引擎在 ClickHouse 中的作用十分關(guān)鍵谈火,直接決定了數(shù)據(jù)如何存儲(chǔ)和讀取侈询、是否支持并發(fā)讀寫、是否支持 index糯耍、支持的 query 種類扔字、是否支持主備復(fù)制等。
- 數(shù)據(jù)的存儲(chǔ)方式和位置温技,寫到哪里以及從哪里讀取數(shù)據(jù)
- 支持哪些查詢以及如何支持革为。
- 并發(fā)數(shù)據(jù)訪問。
- 索引的使用(如果存在)舵鳞。
- 是否可以執(zhí)行多線程請(qǐng)求震檩。
- 數(shù)據(jù)復(fù)制參數(shù)。
具體可看官網(wǎng):https://clickhouse.tech/docs/zh/engines/table-engines/
ClickHouse 的表引擎提供了四個(gè)系列(Log蜓堕、MergeTree抛虏、Integration、Special)大約 28 種表引擎套才,各有各的用途迂猴。比如 Log 系列用來(lái)做小表數(shù)據(jù)分 析,MergeTree 系列用來(lái)做大數(shù)據(jù)量分析背伴,而 Integration 系列則多用于外表數(shù)據(jù)集成沸毁。Log、Special傻寂、Integration 系列的表引擎相對(duì)來(lái)說(shuō)息尺,應(yīng)用場(chǎng)景有限,功能簡(jiǎn)單疾掰,應(yīng)用特殊用途搂誉,MergeTree 系列表引擎又和兩種特殊表引擎(Replicated,Distributed)正交形成多種具備不同功能的 MergeTree 表引擎个绍。
MergeTree 作為家族中最基礎(chǔ)的表引擎勒葱,提供了主鍵索引、數(shù)據(jù)分區(qū)巴柿、數(shù)據(jù)副本和數(shù)據(jù)采樣等基本能力,而家族中其他的表引擎則在 MergeTree 的基礎(chǔ) 之上各有所長(zhǎng):
2.3 MergeTree 引擎工作機(jī)制詳解
MergeTree 系列是官方主推的存儲(chǔ)引擎死遭,支持幾乎所有 ClickHouse 核心功能广恢,該系列中,常用的表引擎有:MergeTree呀潭、ReplacingMergeTree钉迷、 CollapsingMergeTree至非、 VersionedCollapsingMergeTree、 SummingMergeTree糠聪、 AggregatingMergeTree 等荒椭。學(xué)習(xí)好 MergeTree 表引擎的工作機(jī) 制,是應(yīng)用好 ClickHouse 的最基本基礎(chǔ)舰蟆。
關(guān)于 MergeTree 表引擎類型:
- 原生 MergeTree 表引擎主要用于海量數(shù)據(jù)分析趣惠,支持?jǐn)?shù)據(jù)分區(qū)、存儲(chǔ)有序身害、主鍵索引味悄、稀疏索引、數(shù)據(jù) TTL 等塌鸯。MergeTree 支持所有ClickHouse SQL 語(yǔ)法侍瑟,但是有些功能與 MySQL 并不一致,比如在 MergeTree 中主鍵并不用于去重丙猬。
- 為了解決 MergeTree 相同主鍵無(wú)法去重的問題涨颜,ClickHouse 提供了 ReplacingMergeTree 引擎,用來(lái)做去重茧球。ReplacingMergeTree 確保數(shù)據(jù)最終被去重庭瑰,但是無(wú)法保證查詢過(guò)程中主鍵不重復(fù)。因?yàn)橄嗤麈I的數(shù)據(jù)可能被 shard 到不同的節(jié)點(diǎn)袜腥,但是 compaction 只能在一個(gè)節(jié)點(diǎn)中進(jìn)行见擦,而且 optimize 的時(shí)機(jī)也不確定。
- 解決刪除場(chǎng)景羹令,CollapsingMergeTree 引擎要求在建表語(yǔ)句中指定一個(gè)標(biāo)記列 Sign(插入的時(shí)候指定為 1鲤屡,刪除的時(shí)候指定為 -1),后臺(tái) Compaction 時(shí)會(huì)將主鍵相同福侈、Sign 相反的行進(jìn)行折疊酒来,也即刪除。來(lái)消除 ReplacingMergeTree 的限制肪凛。
- 為了解決 CollapsingMergeTree 亂序?qū)懭肭闆r下無(wú)法正常折疊問題堰汉,VersionedCollapsingMergeTree 表引擎在建表語(yǔ)句中新增了一 列 Version,用于在亂序情況下記錄狀態(tài)行與取消行的對(duì)應(yīng)關(guān)系伟墙。主鍵相同翘鸭,且 Version 相同、Sign 相反的行戳葵,在 Compaction 時(shí)會(huì)被刪除就乓。
- 解決聚合場(chǎng)景,ClickHouse 通過(guò) SummingMergeTree 來(lái)支持對(duì)主鍵列進(jìn)行預(yù)先聚合。在后臺(tái) Compaction 時(shí)生蚁,會(huì)將主鍵相同的多行進(jìn)行 sum 求 和噩翠,然后使用一行數(shù)據(jù)取而代之,從而大幅度降低存儲(chǔ)空間占用邦投,提升聚合計(jì)算性能伤锚。同理還有 AggregatingMergeTree用來(lái)預(yù)聚合平均值。
MergeTree 的建表語(yǔ)法:
CREATE TABLE [IF NOT EXISTS] [db_name.]table_name ( name1 [type] [DEFAULT|MATERIALIZED|ALIAS expr], name2 [type] [DEFAUErEMAMLERLALLIZED|ALIAS expr], 省略...
) ENGINE = MergeTree()
[PARTITION BY expr]
[ORDER BY expr]
[PRIMARY KEY expr]
[SAMPLE BY expr]
[SETTINGS name=value, 省略...]
介紹一下其中的幾個(gè)關(guān)鍵選項(xiàng):
- PARTITION BY: 分區(qū)鍵志衣。指定表數(shù)據(jù)以何種標(biāo)準(zhǔn)進(jìn)行分區(qū)屯援。分區(qū)鍵既可以是單個(gè)列字段,也可以通過(guò)元組的形式使用多個(gè)列字段蠢涝,同時(shí)它也支持使用列表達(dá) 式玄呛。選填。如果沒有執(zhí)行分區(qū)字段和二,則所有數(shù)據(jù)徘铝,都在一個(gè)分區(qū)里面: all;
- ORDER BY: 排序鍵,用于指定在一個(gè)數(shù)據(jù)片段內(nèi)惯吕,數(shù)據(jù)以何種標(biāo)準(zhǔn)排序惕它。默認(rèn)情況下主鍵(PRIMARY KEY)與排序鍵相同。必填废登。
- PRIMARY KEY: 主鍵淹魄。聲明后會(huì)依照主鍵字段生成一級(jí)索引。默認(rèn)情況下堡距,主鍵與排序鍵(ORDER BY)相同甲锡,所以通常直接使用 ORDER BY 代為指定主鍵。
- SETTINGS: index_granularity 選項(xiàng)表示索引的粒度羽戒,默認(rèn)值為 8192缤沦。MergeTree 索引在默認(rèn)情況下,每間隔 8192 行數(shù)據(jù)才生成一條索引易稠。選填缸废。
- SAMPLE BY:抽樣表達(dá)式,用于聲明數(shù)據(jù)以何種標(biāo)準(zhǔn)進(jìn)行采樣驶社。選填企量。
注意 settings 中的重要參數(shù):
- index_granularity 默認(rèn)是 8192 = 1024 * 8, 推薦不修改
- index_granularity_bytes 默認(rèn) 10M亡电,需要通過(guò) enable_mixed_granularity_parts 來(lái)開啟
- enable_mixed_granularity_parts 默認(rèn)開啟自適應(yīng)索引粒度
- merge_with_ttl_timeout 提供數(shù)據(jù) TTL 功能;
這里要特別聲明届巩,MergeTree 主鍵索引是稀疏索引!
- 稠密索引: 一條數(shù)據(jù)創(chuàng)建一條索引;
- 稀疏索引: 一段數(shù)據(jù)創(chuàng)建一條索引份乒;
3. ClickHouse 工作原理
本章節(jié)將會(huì)介紹 MergeTree 表引擎的內(nèi)部工作細(xì)節(jié)! 最終就是告訴大家為什么clickhouse做查詢分析那么快?
ClickHouse 從 OLAP 場(chǎng)景需求出發(fā)姆泻,定制開發(fā)了一套全新的高效列式存儲(chǔ)引擎零酪,并且實(shí)現(xiàn)了數(shù)據(jù)有序存儲(chǔ)冒嫡、主鍵索引拇勃、稀疏索引、數(shù)據(jù) Sharding孝凌、數(shù)據(jù) Partitioning方咆、TTL、主備復(fù)制等豐富功能蟀架。這些功能共同為 ClickHouse 極速的分析性能奠定了基礎(chǔ)瓣赂。
- clickhouse 數(shù)據(jù)分區(qū)
- clickhouse 列式存儲(chǔ)
- clickhouse 一級(jí)索引 主鍵索引
- clickhouse 二級(jí)索引 跳數(shù)索引
- clickhouse 數(shù)據(jù)壓縮
- clickhouse 數(shù)據(jù)標(biāo)記
3.1 數(shù)據(jù)分區(qū)
關(guān)于表分區(qū)目錄結(jié)構(gòu): MergeTree 表的分區(qū)目錄物理結(jié)構(gòu),該表有 a,b,date,name 四個(gè)字段。 當(dāng)創(chuàng)建好了這張表之后片拍,那么一次批量插入煌集,就可能形成多個(gè)分區(qū),其實(shí)每個(gè)分區(qū)捌省,就是表存儲(chǔ)目錄中的一個(gè)子文件夾
假設(shè)用一個(gè) 文件夾來(lái)存儲(chǔ)這張表的所有數(shù)據(jù)苫纤,為了提高效率,可以考慮把 表的所有數(shù)據(jù)纲缓,按照某個(gè)維度卷拘,分割成多個(gè)子文件夾,假設(shè)以日期字段為例祝高, 查詢不同的月份栗弟,到表文件夾的不同子文件夾中尋找即可。
引出兩個(gè)問題:
- 分區(qū)文件夾的命名規(guī)則是什么?合并規(guī)則是什么?
- 分區(qū)文件夾的文件列表工闺,各是什么作用乍赫,什么含義?
關(guān)于這些文件的解釋:
- 分區(qū)目錄:20190710_20190711_1_5_1,一個(gè)分區(qū)可能會(huì)有多個(gè)不同的目錄陆蟆,該目錄下存儲(chǔ)該分區(qū)的數(shù)據(jù)及其他各種形式的數(shù)據(jù)雷厂。后臺(tái)會(huì)執(zhí)行合并,把相同分 區(qū)的多個(gè)目錄合并到一個(gè)分區(qū)遍搞。
- checksums.txt:校驗(yàn)文件罗侯。使用二進(jìn)制格式存儲(chǔ)。它保存了余下各類文件(primary.idx溪猿、count.txt等)的 size 大小及 size 的哈希值钩杰,用于快速校 驗(yàn)文件的完整性和正確性。
- columns.txt:列信息文件诊县,使用明文格式存儲(chǔ)讲弄。用于保存此數(shù)據(jù)分區(qū)下的列字段信息 。
- count.txt:計(jì)數(shù)文件依痊,使用明文格式存儲(chǔ)避除。用于記錄當(dāng)前數(shù)據(jù)分區(qū)目錄下數(shù)據(jù)的總行數(shù)怎披。
- primary.idx:一級(jí)索引文件,主鍵索引文件瓶摆。
- xxx.bin:數(shù)據(jù)文件凉逛,使用壓縮格式存儲(chǔ),默認(rèn)為 LZ4 壓縮格式群井,用于存儲(chǔ)某一列的數(shù)據(jù)状飞,每一列都對(duì)應(yīng)一個(gè)該文件,如列 date 為 date.bin书斜。
- xxx.mrk:列字段標(biāo)記文件诬辈。
- xxx.mrk2:列字段標(biāo)記文件,如果使用了自適應(yīng)大小的索引間隔荐吉,則標(biāo)記文件以 .mrk2 命名焙糟,否則以 .mrk 命名。它建立 primary.idx 稀疏索引與 xxx.bin 數(shù)據(jù)文件之間的映射關(guān)系样屠,先通過(guò)主鍵索引找到數(shù)據(jù)的偏移量穿撮,然后去 xxx.bin 數(shù)據(jù)文件中找到真實(shí)數(shù)據(jù)
- 還有二級(jí)索引 和 分區(qū)鍵相關(guān)信息文件,跳數(shù)索引文件等等
關(guān)于表分區(qū)命名規(guī)則:分區(qū)的命名規(guī)則:PartitionID_MinBlockNum_MaxBlockNum_Level
該 blocknum 在該表內(nèi)全局累加瞧哟,每次創(chuàng)建一個(gè)新的分區(qū)目錄的時(shí)候混巧,就會(huì)累加 1。Level 是分區(qū)被合并過(guò)的次數(shù)計(jì)數(shù)勤揩,合并一次則加1咧党。
insert into table values(201905 zhangsan), (201906 lisi), (201906 wangwu); 201905_1_1_0 201906_2_2_0
insert into table values(201905 zhangsan), (201906 lisi), (201906 wangwu); 201905_3_3_0 201906_4_4_0
201905_1_1_0 + 201905_3_3_0 = 201905_1_3_1
201905_3_5_2 + 201905_6_9_3 = 201905_3_9_4
關(guān)于分區(qū)的合并規(guī)則:
3.2 列式存儲(chǔ)
對(duì)于 OLAP 技術(shù)來(lái)說(shuō),一般都是這對(duì)大量行少量列做聚合分析陨亡,所以列式存儲(chǔ)技術(shù)基本可以說(shuō)是 OLAP 必用的技術(shù)方案傍衡。列式存儲(chǔ)相比于行式存儲(chǔ),列式存儲(chǔ)在分析場(chǎng)景下有著許多優(yōu)良的特性负蠕。
- 分析場(chǎng)景中往往需要讀大量行但是少數(shù)幾個(gè)列蛙埂。在行存模式下,數(shù)據(jù)按行連續(xù)存儲(chǔ)遮糖,所有列的數(shù)據(jù)都存儲(chǔ)在一個(gè)block中绣的,不參與計(jì)算的列在IO時(shí)也 要全部讀出,讀取操作被嚴(yán)重放大欲账。而列存模式下屡江,只需要讀取參與計(jì)算的列即可,極大的減低了IO cost赛不,加速了查詢惩嘉。
- 同一列中的數(shù)據(jù)屬于同一類型,壓縮效果顯著踢故,壓縮比高文黎。列存往往有著高達(dá)十倍甚至更高的壓縮比惹苗,節(jié)省了大量的存儲(chǔ)空間,降低了存儲(chǔ)成本耸峭。
- 更高的壓縮比意味著更小的data size桩蓉,從磁盤中讀取相應(yīng)數(shù)據(jù)耗時(shí)更短。
- 自由的壓縮算法選擇抓艳。不同列的數(shù)據(jù)具有不同的數(shù)據(jù)類型触机,適用的壓縮算法也就不盡相同$杌颍可以針對(duì)不同列類型,選擇最合適的壓縮算法片任。
- 高壓縮比偏友,意味著同等大小的內(nèi)存能夠存放更多數(shù)據(jù),系統(tǒng)cache效果更好对供。
3.3 一級(jí)索引
關(guān)于一級(jí)索引: MergeTree 的主鍵使用 PRIMARY KEY 定義位他,待主鍵定義之后,MergeTree 會(huì)依據(jù)index_granularity 間隔(默認(rèn) 8192 行)产场,為數(shù) 據(jù)表生成一級(jí)索引并保存至 primary.idx 文件內(nèi)鹅髓。一級(jí)索引是稀疏索引,意思就是說(shuō):每一段數(shù)據(jù)生成一條索引記錄京景,而不是每一條數(shù)據(jù)都生成索引窿冯, 如果是每一條數(shù)據(jù)都生成索引,則是稠密索引确徙。稀疏索引的好處醒串,就是少量的索引標(biāo)記,就能記錄大量的數(shù)據(jù)區(qū)間位置信息鄙皇,比如不到 24414 條標(biāo)記信 息芜赌,就能為 2E 條數(shù)據(jù)提供索引(算法:200000000 / 8192)。在 ClickHouse 中伴逸,一級(jí)索引常駐內(nèi)存缠沈。總的來(lái)說(shuō): 一級(jí)索引和標(biāo)記文件一一對(duì)齊错蝴,兩個(gè) 索引標(biāo)記之間的數(shù)據(jù)洲愤,就是一個(gè)數(shù)據(jù)區(qū)間,在數(shù)據(jù)文件中漱竖,這個(gè)數(shù)據(jù)區(qū)間的所有數(shù)據(jù)禽篱,生成一個(gè)壓縮數(shù)據(jù)塊。
需要注意的是: ClickHouse 的主鍵索引與 MySQL 等數(shù)據(jù)庫(kù)不同馍惹,它并不用于去重躺率,即便 primary key 相同的行玛界,也可以同時(shí)存在于數(shù)據(jù)庫(kù)中。要想實(shí)現(xiàn)去重效果悼吱,需要結(jié)合具體的表引擎 ReplacingMergeTree慎框、CollapsingMergeTree、VersionedCollapsingMergeTree 實(shí)現(xiàn)后添。這個(gè)在之前的表引擎介紹中講過(guò)笨枯。
3.4 二級(jí)索引
關(guān)于二級(jí)索引: 又稱之為跳數(shù)索引。目的和一級(jí)索引一樣遇西,是為了減少待搜尋的數(shù)據(jù)的范圍馅精。跳數(shù)索引的默認(rèn)是關(guān)閉的,需要通過(guò)參數(shù)來(lái)開啟粱檀,索引生成粒度由 granularity 控制洲敢,如果生成了二級(jí)索引,則會(huì)在分區(qū)目錄下生成額外的:skp_idx_[Column].idx
與 skp_idx_[Column].mrk
文件茄蚯。跳數(shù)索引的生成規(guī)則:按照特定規(guī)則每隔 granularity 個(gè) index_granularity 條數(shù)據(jù)压彭,就會(huì) 生成一條跳數(shù)索引。比如 minmax 跳數(shù)索引渗常,生成的是:granularity 個(gè) index_granularity 條數(shù)據(jù)內(nèi)的最大值最小值生成一條索引壮不,如果將來(lái)需要針對(duì) 構(gòu)建二級(jí)索引的這個(gè)字段求最大值最小值,則可以幫助提高效率皱碘。跳數(shù)索引一共支持四種類型:minmax(最大最小)询一、set(去重集合)、 ngrambf_v1(ngram 分詞布隆索引) 和 tokenbf_v1(標(biāo)點(diǎn)符號(hào)分詞布隆索引)尸执,一張數(shù)據(jù)表支持同時(shí)聲明多個(gè)跳數(shù)索引家凯。比如:
GRANULARITY = 你在創(chuàng)建二級(jí)索引索引的指定的
INDEX_GRANULARITY = 8192 構(gòu)建一條主鍵索引
GRANULARITY * INDEX_GRANULARITY 構(gòu)建一條 二級(jí)索引
CREATE TABLE skip_test(
ID String,
URL String,
Code String,
EventTime Date,
INDEX a ID TYPE minmax GRANULARITY 5,
INDEX b (length(ID) * 8) TYPE set(2) GRANULARITY 5,
INDEX c (ID, Code) TYPE ngrambf_v1(3, 256, 2, O) GRANULARITY 5,
INDEX d ID TYPE tokenbf_v1(256, 2, 0) GRANULARITY 5
) ENGINE= MergeTree()
order by id;
關(guān)于跳數(shù)索引支持的多種類型的區(qū)別:
- minmax:以 index_granularity 為單位,存儲(chǔ)指定表達(dá)式計(jì)算后的 min如失、max 值;在等值和范圍查詢中能夠幫助快速跳過(guò)不滿足要求的塊绊诲,減少 IO。
- set(max_rows):以 index granularity 為單位褪贵,存儲(chǔ)指定表達(dá)式的 distinct value 集合掂之,用于快速判斷等值查詢是否命中該塊,減少 IO脆丁。
- ngrambf_v1(n, size_of_bloom_filter_in_bytes, number_of_hash_functions, random_seed):將 string 進(jìn)行 ngram 分詞后世舰,構(gòu)建 bloom filter,能夠優(yōu)化 等值槽卫、like跟压、in 等查詢條件.
- tokenbf_v1(size_of_bloom_filter_in_bytes, number_of_hash_functions, random_seed):與 ngrambf_v1 類似,區(qū)別是不使用 ngram 進(jìn)行分詞歼培,而是通過(guò)標(biāo)點(diǎn)符號(hào)進(jìn)行詞語(yǔ)分割震蒋。
- bloom_filter([false_positive]):對(duì)指定列構(gòu)建 bloom filter茸塞,用于加速 等值、like查剖、in 等查詢條件的執(zhí)行钾虐。
3.5 數(shù)據(jù)壓縮
關(guān)于數(shù)據(jù)壓縮: ClickHouse 的數(shù)據(jù)存儲(chǔ)文件 column.bin 中存儲(chǔ)是一列的數(shù)據(jù),由于一列是相同類型的數(shù)據(jù)笋庄,所以方便高效壓縮效扫。在進(jìn)行壓縮的時(shí)候,請(qǐng) 注意:一個(gè)壓縮數(shù)據(jù)塊由頭信息和壓縮數(shù)據(jù)兩部分組成直砂,頭信息固定使用 9 位字節(jié)表示菌仁,具體由 1 個(gè) UInt8(1字節(jié))整型和 2 個(gè) UInt32(4字節(jié))整型 組成,分別代表使用的壓縮算法類型哆键、壓縮后的數(shù)據(jù)大小和壓縮前的數(shù)據(jù)大小掘托。每個(gè)壓縮數(shù)據(jù)塊的體積,按照其壓縮前的數(shù)據(jù)字節(jié)大小籍嘹,都被嚴(yán)格控制在 64KB~1MB,其上下限分別由 min_compress_block_size(默認(rèn)65536=64KB)與 max_compress_block_size(默認(rèn)1048576=1M)參數(shù)指定弯院。具體壓 縮規(guī)則:
原理的說(shuō)法: 每 8192 條記錄辱士,其實(shí)就是一條一級(jí)索引、一個(gè)索引區(qū)間壓縮成一個(gè)數(shù)據(jù)塊听绳。
1颂碘、單個(gè)批次數(shù)據(jù) size < 64KB:如果單個(gè)批次數(shù)據(jù)小于 64KB,則繼續(xù)獲取下一批數(shù)據(jù)椅挣,直至累積到size >= 64KB時(shí)头岔,生成下一個(gè)壓縮數(shù)據(jù)塊。如果平均每條 記錄小于8byte鼠证,多個(gè)數(shù)據(jù)批次壓縮成一個(gè)數(shù)據(jù)塊
2峡竣、單個(gè)批次數(shù)據(jù) 64KB <= size <=1MB:如果單個(gè)批次數(shù)據(jù)大小恰好在 64KB 與 1MB 之間,則直接生成下一個(gè)壓縮數(shù)據(jù)塊量九。
3适掰、單個(gè)批次數(shù)據(jù) size > 1MB:如果單個(gè)批次數(shù)據(jù)直接超過(guò) 1MB,則首先按照 1MB 大小截?cái)嗖⑸上乱粋€(gè)壓縮數(shù)據(jù)塊荠列。剩余數(shù)據(jù)繼續(xù)依照上述規(guī)則執(zhí)行类浪。此時(shí), 會(huì)出現(xiàn)一個(gè)批次數(shù)據(jù)生成多個(gè)壓縮數(shù)據(jù)塊的情況肌似。如果平均每條記錄的大小超過(guò) 128byte,則會(huì)把當(dāng)前這一個(gè)批次的數(shù)據(jù)壓縮成多個(gè)數(shù)據(jù)塊费就。
總結(jié):
- 在一個(gè) xxx.bin 字段存儲(chǔ)文件中,并不是一個(gè)壓縮塊對(duì)應(yīng)到一條一級(jí)索引川队,而是每 8192 條數(shù)據(jù)力细,構(gòu)建一條一級(jí)索引睬澡。
- 一個(gè) [Column].bin 其實(shí)是由一個(gè)個(gè)的壓縮數(shù)據(jù)塊組成的。每個(gè)壓縮塊的大小在: 64kb - 1M 之間艳汽。
注意:一個(gè)壓縮數(shù)據(jù)塊由頭信息和壓縮數(shù)據(jù)兩部分組成猴贰。頭信息固定使用9位字節(jié)表示,具體由1個(gè)UInt8(1字節(jié))整型和 2 個(gè) UInt32(4字節(jié))整型組成河狐,分別代表使用的壓縮算法類型米绕、壓縮后的數(shù)據(jù)大小和壓縮前的數(shù)據(jù)大小馋艺;
我們來(lái)看看 column.bin 數(shù)據(jù)文件的組成:
3.6 數(shù)據(jù)標(biāo)記
關(guān)于數(shù)據(jù)標(biāo)記:數(shù)據(jù)標(biāo)記文件也與 .bin 文件一一對(duì)應(yīng)栅干,一級(jí)索引和數(shù)據(jù)之間的橋梁。即每一個(gè)列字段 [Column].bin 文件都有一個(gè)與之對(duì)應(yīng)的 [Column].mrk2 數(shù)據(jù)標(biāo)記文件捐祠,用于記錄數(shù)據(jù)在 .bin 文件中的偏移量信息碱鳞。一行標(biāo)記數(shù)據(jù)使用一個(gè)元組表示,元組內(nèi)包含兩個(gè)整型數(shù)值的偏移量信息踱蛀。 它們分別表示在此段數(shù)據(jù)區(qū)間內(nèi)窿给,在對(duì)應(yīng)的 .bin 壓縮文件中,壓縮數(shù)據(jù)塊的起始偏移量;以及將該數(shù)據(jù)壓縮塊解壓后率拒,其未壓縮數(shù)據(jù)的起始偏移量崩泡。每 一行標(biāo)記數(shù)據(jù)都表示了一個(gè)片段的數(shù)據(jù)(默認(rèn)8192行)在 .bin 壓縮文件中的讀取位置信息。標(biāo)記數(shù)據(jù)與一級(jí)索引數(shù)據(jù)不同猬膨,它并不能常駐內(nèi)存角撞,而是使 用 LRU(最近最少使用)緩存策略加快其取用速度。
總結(jié)數(shù)據(jù)讀取流程: 先根據(jù)一級(jí)索引勃痴,找到標(biāo)記文件中的對(duì)應(yīng)數(shù)據(jù)壓縮塊信息(壓縮塊在 .bin 文件中的起始偏移量和未壓縮之前該條數(shù)據(jù)的是偏移量) 然后從 .bin 文件中谒所,把壓縮塊加載到內(nèi)存,解壓縮之后沛申,執(zhí)行讀取劣领。
數(shù)據(jù)標(biāo)記文件也與 .bin 文件一一對(duì)應(yīng)。即每一個(gè)列字段 [Column].bin 文件都有一個(gè)與之對(duì)應(yīng)的 [Column].mrk 數(shù)據(jù)標(biāo)記文件污它,用于記錄數(shù)據(jù)在 .bin 文 件中的偏移量信息剖踊。
標(biāo)記文件的最重要的作用,就是建立了主鍵索引到數(shù)據(jù)文件的數(shù)據(jù)的映射! MergeTree 具體是如何定位壓縮數(shù)據(jù)塊并讀取數(shù)據(jù)的呢?
- 第一步:根據(jù)標(biāo)記文件中的信息衫贬,找到對(duì)應(yīng)的壓縮數(shù)據(jù)塊德澈,讀取壓縮數(shù)據(jù)塊,執(zhí)行解壓縮固惯;
- 第二步:從解壓縮的數(shù)據(jù)塊中梆造,以 index_granularity 的粒度加載數(shù)據(jù)到內(nèi)存中,執(zhí)行查詢,直至找到結(jié)果數(shù)據(jù)镇辉;
4 ClickHouse 核心查詢流程
數(shù)據(jù)查詢的本質(zhì)屡穗,可以看作一個(gè)不斷減小數(shù)據(jù)范圍的過(guò)程。在最理想的情況下忽肛,MergeTree 首先可以依次借助分區(qū)索引村砂、一級(jí)索引和二級(jí)索引,將數(shù)據(jù) 掃描范圍縮至最小屹逛。然后再借助數(shù)據(jù)標(biāo)記础废,將需要解壓與計(jì)算的數(shù)據(jù)范圍縮至最小。
select name from student where date = 201905;
- 指定分區(qū)
- 指定字段(xxx.bin )
- 根據(jù)一級(jí)索引(primary.idx)定位到 標(biāo)記文件 (name.mrk2) 中的那一條記錄
- 掃描對(duì)應(yīng)字段的 mark 標(biāo)記文件 獲取兩個(gè)偏移量信息(當(dāng)前要查找的數(shù)據(jù)罕模,處于這個(gè) .bin 數(shù)據(jù)文件中的那個(gè) 壓縮數(shù)據(jù)塊评腺,這個(gè)壓縮數(shù)據(jù)塊在 .bin 文件的偏移量, 這個(gè)壓縮數(shù)據(jù)塊解壓縮出來(lái)之后淑掌,要找的數(shù)據(jù)在當(dāng)前這個(gè)壓縮數(shù)據(jù)塊的偏移量)
- 根據(jù)第一個(gè)偏移量去 .bin 文件中定位到一個(gè) 壓縮數(shù)據(jù)快
- 讀取數(shù)據(jù)到內(nèi)存執(zhí)行解壓縮
- 根據(jù)第二個(gè)偏移量去內(nèi)存解壓縮數(shù)據(jù)中找到對(duì)應(yīng)的數(shù)據(jù)
提高數(shù)據(jù)查詢效率的核心原則只有一個(gè): 誰(shuí)做的輔助動(dòng)作能快速的幫助我們?nèi)タ焖俳档痛褜さ臄?shù)據(jù)范圍
分布式系統(tǒng)的核心思想: 分而治之蒿讥,必須提供一套架構(gòu)方便用戶的請(qǐng)求被快速的定位到某個(gè)單臺(tái)服務(wù)器去處理。一般來(lái)說(shuō)抛腕,這個(gè)服務(wù)器處理這個(gè)請(qǐng)求芋绸,都是很快的!