日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

OLAP(四):ClickHouse

發(fā)布時(shí)間:2023/12/20 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 OLAP(四):ClickHouse 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

引言

什么是ClickHouse? | ClickHouse文檔

ClickHouse是近年來備受關(guān)注的開源列式數(shù)據(jù)庫,主要用于數(shù)據(jù)分析(OLAP)領(lǐng)域。目前國內(nèi)各個(gè)大廠紛紛跟進(jìn)大規(guī)模使用:

  • 今日頭條內(nèi)部用ClickHouse來做用戶行為分析,內(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ù)增量十多億,近百萬次查詢請(qǐng)求。
  • 快手內(nèi)部也在使用ClickHouse,存儲(chǔ)總量大約10PB, 每天新增200TB, 90%查詢小于3S。
  • 阿里內(nèi)部專門孵化了相應(yīng)的云數(shù)據(jù)庫ClickHouse,并且在包括手機(jī)淘寶流量分析在內(nèi)的眾多業(yè)務(wù)被廣泛使用。

????????在開源的短短幾年時(shí)間內(nèi),ClickHouse就俘獲了諸多大廠的“芳心”,并且在Github上的活躍度超越了眾多老牌的經(jīng)典開源項(xiàng)目,如Presto、Druid、Impala、Geenplum等;其受歡迎程度和社區(qū)火熱程度可見一斑。

相比HBase和Redis這類NoSQL數(shù)據(jù)庫,ClickHouse使用關(guān)系模型描述數(shù)據(jù)并提供了傳統(tǒng)數(shù)據(jù)庫的概念 ( 數(shù)據(jù)庫、表、視圖和函數(shù)等 )。與此同時(shí),ClickHouse完全使用SQL作為查詢語言 ( 支持GROUP BY、ORDER BY、JOIN、IN等大部分標(biāo)準(zhǔn)SQL ),這使得它平易近人,容易理解和學(xué)習(xí)。

關(guān)系模型相比文檔和鍵值對(duì)等其他模型,擁有更好的描述能力,也能夠更加清晰地表述實(shí)體間的關(guān)系。更重要的是,在OLAP領(lǐng)域,已有的大量數(shù)據(jù)建模工作都是基于關(guān)系模型展開的 ( 星型模型、雪花模型乃至寬表模型 )。ClickHouse使用了關(guān)系模型,所以將構(gòu)建在傳統(tǒng)關(guān)系型數(shù)據(jù)庫或數(shù)據(jù)倉庫之上的系統(tǒng)遷移到ClickHouse的成本會(huì)變得更低,可以直接沿用之前的經(jīng)驗(yàn)成果。

--建表語句 create table t_order_mt( id UInt32, sku_id String, total_amount Decimal(16,2), --total_amount Decimal(16,2) TTL create_time+interval 10 SECOND, --到期后,指定的字段數(shù)據(jù)歸 0 create_time Datetime ) engine =MergeTree --engine =ReplacingMergeTree(create_time) --填入的參數(shù)為版本字段,重復(fù)數(shù)據(jù)保留版本字段值最大的。如果不填版本字段,默認(rèn)按照插入順序保留最后一條。 --繼承 MergeTree,只是多了一個(gè)去重的功能,數(shù)據(jù)的去重只會(huì)在合并的過程中出現(xiàn) partition by toYYYYMMDD(create_time) --可選 primary key (id) --可選 order by (id,sku_id); --必選--表級(jí) TTL alter table t_order_mt3 MODIFY TTL create_time + INTERVAL 10 SECOND;--插入數(shù)據(jù) insert into t_order_mt values (101,'sku_001',1000.00,'2020-06-01 12:00:00') , (102,'sku_002',2000.00,'2020-06-01 11:00:00'), (102,'sku_004',2500.00,'2020-06-01 12:00:00'), (102,'sku_002',2000.00,'2020-06-01 13:00:00')--刪除操作 alter table t_order_smt delete where sku_id ='sku_001';--修改操作 alter table t_order_smt update total_amount=toDecimal32(2000.00,2) where id =102;--新增字段 alter table tableName add column newcolname String after col1;--修改字段類型 alter table tableName modify column newcolname String;--刪除字段 alter table tableName drop column newcolname;

-- 導(dǎo)出數(shù)據(jù) clickhouse-client --query "select * from t_order_mt where create_time='2020-06-01 12:00:00'" --format CSVWithNames> /opt/module/data/rs1.csv

????????可以發(fā)現(xiàn)在執(zhí)行了update,delete操作之后數(shù)據(jù)目錄會(huì)生成文件mutation_5.txt,mutation_6.txt。
此外還有在同名的
目錄下在末尾增加了_5 ,_6的后綴。
可以看到mutation_5.txt和mutation_6.txt 是日志文件,完整的記錄了update和delete操作語句和時(shí)間。
mutation_id:生成對(duì)應(yīng)的日志文件用于記錄相關(guān)的信息。
數(shù)據(jù)刪除的過程是以數(shù)據(jù)表的每個(gè)分區(qū)目錄為單位,將所有目錄重寫為新的目錄,在目錄的命名規(guī)則是在原有的名稱上加上 block_numbers.number
數(shù)據(jù)的在重寫的過程中會(huì)講所需要?jiǎng)h除的數(shù)據(jù)去掉。舊的數(shù)據(jù)并不會(huì)立即刪除,而是被標(biāo)記為非激活狀態(tài)(active =0),
等到MergeTree引擎的下一次合并動(dòng)作觸發(fā)的時(shí)候,
這些非活動(dòng)目錄才會(huì)被真正的從物理上刪除。
?

數(shù)據(jù) TTL (Time To Live)

TTL 即 Time To Live,MergeTree 提供了可以管理數(shù)據(jù)或者列的生命周期的功能。
(1) 列級(jí)別 TTL
? ?創(chuàng)建測試表

create table t_order_mt3( id UInt32, sku_id String, total_amount Decimal(16,2) TTL create_time+interval 10 SECOND, create_time Datetime ) engine =MergeTree partition by toYYYYMMDD(create_time) primary key (id) order by (id, sku_id);

? ?插入數(shù)據(jù)(注意:根據(jù)實(shí)際時(shí)間改變)

insert into t_order_mt3 values (106,'sku_001',1000.00,'2020-06-12 22:52:30'), (107,'sku_002',2000.00,'2020-06-12 22:52:30'), (110,'sku_003',600.00,'2020-06-13 12:00:00');?

? ?手動(dòng)合并,查看效果 到期后,指定的字段數(shù)據(jù)歸 0

?表級(jí) TTL
下面的這條語句是數(shù)據(jù)會(huì)在 create_time 之后 10 秒丟失
alter table t_order_mt3 MODIFY TTL create_time + INTERVAL 10 SECOND;
涉及判斷的字段必須是 Date 或者 Datetime 類型,推薦使用分區(qū)的日期字段。
能夠使用的時(shí)間周期:
- SECOND
- MINUTE
- HOUR
- DAY
- WEEK

4 ?MergeTree/ReplacingMergeTree?數(shù)據(jù)更新

ClickHouse 中最強(qiáng)大的表引擎當(dāng)屬 MergeTree(合并樹)引擎及該系列(*MergeTree)中的其他引擎,支持索引和分區(qū),地位可以相當(dāng)于 innodb 之于 Mysql。 而且基于MergeTree,還衍生除了很多小弟,也是非常有特色的引擎。

5 ?ReplacingMergeTree

????????ReplacingMergeTree 是 MergeTree 的一個(gè)變種,它存儲(chǔ)特性完全繼承 MergeTree,只是多了一個(gè)去重的功能。 盡管 MergeTree 可以設(shè)置主鍵,但是 primary key 其實(shí)沒有唯一約束的功能。如果你想處理掉重復(fù)的數(shù)據(jù),可以借助這個(gè) ReplacingMergeTree。

? ?去重時(shí)機(jī)
????????數(shù)據(jù)的去重只會(huì)在合并的過程中出現(xiàn)。合并會(huì)在未知的時(shí)間在后臺(tái)進(jìn)行,所以你無法預(yù)
先作出計(jì)劃。有一些數(shù)據(jù)可能仍未被處理。

? ?去重范圍
????????如果表經(jīng)過了分區(qū),去重只會(huì)在分區(qū)內(nèi)部進(jìn)行去重,不能執(zhí)行跨分區(qū)的去重。所以 ReplacingMergeTree 能力有限, ReplacingMergeTree 適用于在后臺(tái)清除重復(fù)的數(shù)據(jù)以節(jié)省空間,但是它不保證沒有重復(fù)的數(shù)據(jù)出現(xiàn)。

? ?案例演示
? ?創(chuàng)建表

create table t_order_rmt( id UInt32, sku_id String, total_amount Decimal(16,2) , create_time Datetime ) engine =ReplacingMergeTree(create_time) partition by toYYYYMMDD(create_time) primary key (id) order by (id, sku_id);

向表中插入數(shù)據(jù)

insert into t_order_rmt values (101,'sku_001',1000.00,'2020-06-01 12:00:00') , (102,'sku_002',2000.00,'2020-06-01 11:00:00'), (102,'sku_004',2500.00,'2020-06-01 12:00:00'), (102,'sku_002',2000.00,'2020-06-01 13:00:00'), (102,'sku_002',12000.00,'2020-06-01 13:00:00'), (102,'sku_002',600.00,'2020-06-02 12:00:00');

? ?執(zhí)行第一次查詢
hadoop202 :) select * from t_order_rmt;


? ?手動(dòng)合并
OPTIMIZE TABLE t_order_rmt FINAL;
? ?再執(zhí)行一次查詢
hadoop202 :) select * from t_order_rmt;?

?

?通過測試得到結(jié)論

  • 實(shí)際上是使用 order by 字段作為唯一鍵
  • 去重不能跨分區(qū)
  • 只有合并分區(qū)才會(huì)進(jìn)行去重
  • 認(rèn)定重復(fù)的數(shù)據(jù)保留,版本字段值最大的
  • 如果版本字段相同則按插入順序保留最后一筆

ClickHouse的組件架構(gòu)

下圖是一個(gè)典型的ClickHouse集群部署結(jié)構(gòu)圖,符合經(jīng)典的share-nothing架構(gòu)。

ClickHouse 采用典型的分組式的分布式架構(gòu),具體集群架構(gòu)如上圖所示:

  • Shard:集群內(nèi)劃分為多個(gè)分片或分組(Shard 0 … Shard N),通過 Shard 的線性擴(kuò)展能力,支持海量數(shù)據(jù)的分布式存儲(chǔ)計(jì)算。
  • Node:每個(gè) Shard 內(nèi)包含一定數(shù)量的節(jié)點(diǎn)(Node,即進(jìn)程),同一 Shard 內(nèi)的節(jié)點(diǎn)互為副本,保障數(shù)據(jù)可靠。ClickHouse 中副本數(shù)可按需建設(shè),且邏輯上不同 Shard 內(nèi)的副本數(shù)可不同。
  • ZooKeeper Service:集群所有節(jié)點(diǎn)對(duì)等,節(jié)點(diǎn)間通過 ZooKeeper 服務(wù)進(jìn)行分布式協(xié)調(diào)。

????????整個(gè)集群分為多個(gè)shard(分片),不同shard之間數(shù)據(jù)彼此隔離;在一個(gè)shard內(nèi)部,可配置一個(gè)或多個(gè)replica(副本),互為副本的2個(gè)replica之間通過專有復(fù)制協(xié)議保持最終一致性。

????????ClickHouse根據(jù)表引擎將表分為本地表和分布式表,兩種表在建表時(shí)都需要在所有節(jié)點(diǎn)上分別建立。其中本地表只負(fù)責(zé)當(dāng)前所在server上的寫入、查詢請(qǐng)求;而分布式表則會(huì)按照特定規(guī)則,將寫入請(qǐng)求和查詢請(qǐng)求進(jìn)行拆解,分發(fā)給所有server,并且最終匯總請(qǐng)求結(jié)果。

多主架構(gòu)(對(duì)等架構(gòu))

HDFS、Spark、HBase和Elasticsearch這類分布式系統(tǒng),都采用了Master-Slave主從架構(gòu),由一個(gè)管控節(jié)點(diǎn)作為Leader統(tǒng)籌全局。而ClickHouse則采用Multi-Master多主架構(gòu),集群中的每個(gè)節(jié)點(diǎn)角色對(duì)等,客戶端訪問任意一個(gè)節(jié)點(diǎn)都能得到相同的效果。這種多主的架構(gòu)有許多優(yōu)勢,例如對(duì)等的角色使系統(tǒng)架構(gòu)變得更加簡單,不用再區(qū)分主控節(jié)點(diǎn)、數(shù)據(jù)節(jié)點(diǎn)和計(jì)算節(jié)點(diǎn),集群中的所有節(jié)點(diǎn)功能相同。所以它天然規(guī)避了單點(diǎn)故障的問題,非常適合用于多數(shù)據(jù)中心、異地多活的場景。

一、ClickHouse存儲(chǔ)層

????????ClickHouse從OLAP場景需求出發(fā),定制開發(fā)了一套全新的高效列式存儲(chǔ)引擎,并且實(shí)現(xiàn)了數(shù)據(jù)列式存儲(chǔ)、有序存儲(chǔ)、主鍵索引、稀疏索引、數(shù)據(jù)Sharding、數(shù)據(jù)Partitioning、TTL、主備復(fù)制等豐富功能。以上功能共同為ClickHouse極速的分析性能奠定了基礎(chǔ)。

一、列式存儲(chǔ)

Hadoop 生態(tài)組件通常依賴 HDFS 作為底層的數(shù)據(jù)存儲(chǔ),ClickHouse?使用本地盤來自己管理數(shù)據(jù),官方推薦使用 SSD 作為存儲(chǔ)介質(zhì)來提升性能。

與行存將每一行的數(shù)據(jù)連續(xù)存儲(chǔ)不同,列存將每一列的數(shù)據(jù)連續(xù)存儲(chǔ)

列式存儲(chǔ):每個(gè)數(shù)據(jù)分區(qū)內(nèi)部,采用列式存儲(chǔ),每個(gè)列涉及兩個(gè)文件,分別是存儲(chǔ)數(shù)據(jù)的 .bin 文件和存儲(chǔ)偏移等索引信息的 .mrk2 文件。

相比于行式存儲(chǔ),列式存儲(chǔ)在分析場景下有著許多優(yōu)良的特性。

  • 對(duì)于列的聚合,計(jì)數(shù),求和等統(tǒng)計(jì)操作原因優(yōu)于行式存儲(chǔ)。
  • 由于某一列的數(shù)據(jù)類型都是相同的,針對(duì)于數(shù)據(jù)存儲(chǔ)更容易進(jìn)行數(shù)據(jù)壓縮,每一列選擇更優(yōu)的數(shù)據(jù)壓縮算法,大大提高了數(shù)據(jù)的壓縮比重。
  • 由于數(shù)據(jù)壓縮比更好,一方面節(jié)省了磁盤空間,另一方面對(duì)于 cache 也有了更大的發(fā)揮空間。

1)分析場景中往往需要讀大量行但是少數(shù)幾個(gè)列。在行存模式下,數(shù)據(jù)按行連續(xù)存儲(chǔ),所有列的數(shù)據(jù)都存儲(chǔ)在一個(gè)block中,不參與計(jì)算的列在IO時(shí)也要全部讀出,讀取操作被嚴(yán)重放大。而列存模式下,只需要讀取參與計(jì)算的列即可,極大的減低了IO cost,加速了查詢。

2)同一列中的數(shù)據(jù)屬于同一類型,壓縮效果顯著。列存往往有著高達(dá)十倍甚至更高的壓縮比,節(jié)省了大量的存儲(chǔ)空間,降低了存儲(chǔ)成本。

3)更高的壓縮比意味著更小的data size,從磁盤中讀取相應(yīng)數(shù)據(jù)耗時(shí)更短。

4)自由的壓縮算法選擇不同列的數(shù)據(jù)具有不同的數(shù)據(jù)類型,適用的壓縮算法也就不盡相同。可以針對(duì)不同列類型,選擇最合適的壓縮算法。

5)高壓縮比,意味著同等大小的內(nèi)存能夠存放更多數(shù)據(jù),系統(tǒng)cache效果更好。

官方數(shù)據(jù)顯示,通過使用列存,在某些分析場景下,能夠獲得100倍甚至更高的加速效應(yīng)。

二、數(shù)據(jù)有序存儲(chǔ) (?sort by?)

ClickHouse支持在建表時(shí),指定將數(shù)據(jù)按照某些列進(jìn)行sort by。

數(shù)據(jù)排序:每個(gè)數(shù)據(jù)分區(qū)內(nèi)部,所有列的數(shù)據(jù)是按照 ORDER BY 列進(jìn)行排序的。可以理解為:對(duì)于生成這個(gè)分區(qū)的原始記錄行,先按 ORDER BY 列進(jìn)行排序,然后再按列拆分存儲(chǔ)。

order by(必選)
order by 設(shè)定了分區(qū)內(nèi)的數(shù)據(jù)按照哪些字段順序進(jìn)行有序保存。
order by 是 MergeTree 中唯一一個(gè)必填項(xiàng),甚至比 primary key 還重要,因?yàn)楫?dāng)用戶不設(shè)置主鍵的情況,很多處理會(huì)依照 order by 的字段進(jìn)行處理(比如后面會(huì)講的去重和匯總)。

????????排序后,保證了相同sort key的數(shù)據(jù)在磁盤上連續(xù)存儲(chǔ),且有序擺放。在進(jìn)行等值、范圍查詢時(shí),where條件命中的數(shù)據(jù)都緊密存儲(chǔ)在一個(gè)或若干個(gè)連續(xù)的Block中,而不是分散的存儲(chǔ)在任意多個(gè)Block, 大幅減少需要IO的block數(shù)量。另外,連續(xù)IO也能夠充分利用操作系統(tǒng)page cache的預(yù)取能力,減少page fault。

數(shù)據(jù)在批量插入時(shí),通常是按原始產(chǎn)生的順序組織,對(duì)于每個(gè)列的維度,都無法保證記錄確定的存儲(chǔ)順序;而實(shí)際的場景中,比如上述的?students?表,數(shù)據(jù)經(jīng)常需要按?id?順序進(jìn)行組織或分析,ClickHouse 支持?jǐn)?shù)據(jù)在存儲(chǔ)時(shí),指定按某個(gè)/些列排序存儲(chǔ),在數(shù)據(jù)寫入到文件之前,ClickHouse 會(huì)對(duì)數(shù)據(jù)先進(jìn)行排序,然后按列進(jìn)行存儲(chǔ)。?stduents?表 ORDER BY?id?之后,實(shí)際存儲(chǔ)順序如下。

三、主鍵索引( primary key )?

????????ClickHouse支持主鍵索引,它將每列數(shù)據(jù)按照index granularity(默認(rèn)8192行)進(jìn)行劃分,每個(gè)index granularity的開頭第一行被稱為一個(gè)mark行。主鍵索引存儲(chǔ)該mark行對(duì)應(yīng)的primary key的值。

主鍵索引:主鍵默認(rèn)與 ORDER BY 列一致,或?yàn)?ORDER BY 列的前綴。由于整個(gè)分區(qū)內(nèi)部是有序的,且切割為數(shù)據(jù)塊存儲(chǔ),ClickHouse 抽取每個(gè)數(shù)據(jù)塊第一行的主鍵,生成一份稀疏的排序索引,可在查詢時(shí)結(jié)合過濾條件快速裁剪數(shù)據(jù)塊。

????????對(duì)于where條件中含有primary key的查詢,通過對(duì)主鍵索引進(jìn)行二分查找,能夠直接定位到對(duì)應(yīng)的index granularity,避免了全表掃描從而加速查詢。

????????index granularity: 直接翻譯的話就是索引粒度,指在稀疏索引中兩個(gè)相鄰索引對(duì)應(yīng)數(shù)據(jù)的間隔。ClickHouse 中的 MergeTree 默認(rèn)是 8192。官方不建議修改這個(gè)值,除非該列存在大量重復(fù)值,比如在一個(gè)分區(qū)中幾萬行才有一個(gè)不同數(shù)據(jù)。

????????但是值得注意的是:ClickHouse的主鍵索引與MySQL等數(shù)據(jù)庫不同,它并不用于去重,即便primary key相同的行,也可以同時(shí)存在于數(shù)據(jù)庫中。要想實(shí)現(xiàn)去重效果,需要結(jié)合具體的表引擎ReplacingMergeTree、CollapsingMergeTree、VersionedCollapsingMergeTree實(shí)現(xiàn),我們會(huì)在未來的文章系列中再進(jìn)行詳細(xì)解讀。

????????ClickHouse 中的主鍵,和其他數(shù)據(jù)庫不太一樣,它只提供了數(shù)據(jù)的一級(jí)索引,但是卻不是唯一約束。這就意味著是可以存在相同 primary key 的數(shù)據(jù)的。主鍵的設(shè)定主要依據(jù)是查詢語句中的 where 條件。

ClickHouse 里的 Primary Key 沒有唯一性約束,通常情況下,用戶無需顯式指定 Primary Key;Sorting Key 即為 Primary Key。兩者也可以不同,但 Primary Key 必須為 Sorting Key 的前綴。

ClickHouse 針對(duì) Primary 建立了單獨(dú)索引,同樣是以?index_granularity行為一個(gè)索引單元 ,因?yàn)閿?shù)據(jù)是按 Primary Key 順序組織的,這個(gè)索引能快速的根據(jù) Primary Key 的值來定位對(duì)應(yīng)的數(shù)據(jù)。students表中 Primary Key 沒有指定,則 id 列即為 Primary Key,其索引如下所示。

當(dāng)查詢指定 Primary 的范圍時(shí),就可以快速根據(jù) primary.idx 索引信息定位到對(duì)應(yīng)的 granule,從而確定 data 文件的掃描范圍。

三、稀疏索引

????????ClickHouse支持對(duì)任意列創(chuàng)建任意數(shù)量的稀疏索引。其中被索引的value可以是任意的合法SQL Expression,并不僅僅局限于對(duì)column value本身進(jìn)行索引。之所以叫稀疏索引,是因?yàn)樗举|(zhì)上是對(duì)一個(gè)完整index granularity(默認(rèn)8192行)的統(tǒng)計(jì)信息,并不會(huì)具體記錄每一行在文件中的位置。目前支持的稀疏索引類型包括:

  • minmax: 以index granularity為單位,存儲(chǔ)指定表達(dá)式計(jì)算后的min、max值;在等值和范圍查詢中能夠幫助快速跳過不滿足要求的塊,減少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)行分詞,而是通過標(biāo)點(diǎn)符號(hào)進(jìn)行詞語分割。
  • bloom_filter([false_positive]):對(duì)指定列構(gòu)建bloom filter,用于加速等值、like、in等查詢條件的執(zhí)行。

稀疏索引:

對(duì)于 Primary Key,ClickHouse 可以通過索引加速查詢,如果查詢條件是非 Primary Key,則默認(rèn)需要掃描數(shù)據(jù)列的所有數(shù)據(jù)進(jìn)行條件過濾;為了加速其他列的查詢,ClickHouse 支持 Skip Index ,用于快速過濾數(shù)據(jù)塊里是否包含滿足條件的數(shù)據(jù),Skip Index 主要包括。

  • minmax,針對(duì)列存數(shù)據(jù)塊,記錄塊內(nèi)最大,最小值用于過濾。
  • set(max_rows),為該列的數(shù)據(jù)存儲(chǔ)不重復(fù)的取值集合,用于過濾,適用于列數(shù)據(jù)有取值較少,但每個(gè)取值數(shù)量較多的場景(即 cardinality 比較低的列)
  • bloomfilter,對(duì)數(shù)據(jù)列的取值建立 bloomfilter 索引數(shù)據(jù)用于快速過濾。
  • ngram、token,為列數(shù)據(jù)的分詞建立 bloomfilter 索引用于快速過濾。
  • 以 minmax 為例,針對(duì) score 列建立 minmax index, GRANULARITY 為2,也就是針對(duì)每2個(gè)索引單元(index_granularity行)對(duì)應(yīng)一個(gè)索引信息。比如要查詢分?jǐn)?shù)小于 80 的所有學(xué)生的信息,則可以快速過濾掉前面兩個(gè)索引單元。

    五、數(shù)據(jù)Sharding分片( Distributed )?分塊

    ????????副本雖然能夠提高數(shù)據(jù)的可用性,降低丟失風(fēng)險(xiǎn),但是每臺(tái)服務(wù)器實(shí)際上必須容納全量數(shù)據(jù),對(duì)數(shù)據(jù)的橫向擴(kuò)容沒有解決。要解決數(shù)據(jù)水平切分的問題,需要引入分片的概念。通過分片把一份完整的數(shù)據(jù)進(jìn)行切分,不同的分片分布到不同的節(jié)點(diǎn)上,再通過 Distributed 表引擎把數(shù)據(jù)拼接起來一同使用。

    數(shù)據(jù)分塊:每個(gè)列的數(shù)據(jù)文件中,實(shí)際是分塊存儲(chǔ)的,方便數(shù)據(jù)壓縮及查詢裁剪,每個(gè)塊中的記錄數(shù)不超過 index_granularity,默認(rèn) 8192。

    ????????ClickHouse支持單機(jī)模式,也支持分布式集群模式。在分布式模式下,ClickHouse會(huì)將數(shù)據(jù)分為多個(gè)分片,并且分布到不同節(jié)點(diǎn)上。不同的分片策略在應(yīng)對(duì)不同的SQL Pattern時(shí),各有優(yōu)勢。ClickHouse提供了豐富的sharding策略,讓業(yè)務(wù)可以根據(jù)實(shí)際需求選用。

    • 1) random隨機(jī)分片:寫入數(shù)據(jù)會(huì)被隨機(jī)分發(fā)到分布式集群中的某個(gè)節(jié)點(diǎn)上。
    • 2) constant固定分片:寫入數(shù)據(jù)會(huì)被分發(fā)到固定一個(gè)節(jié)點(diǎn)上。
    • 3)column value分片:按照某一列的值進(jìn)行hash分片。
    • 4)自定義表達(dá)式分片:指定任意合法表達(dá)式,根據(jù)表達(dá)式被計(jì)算后的值進(jìn)行hash分片。

    數(shù)據(jù)分片,讓ClickHouse可以充分利用整個(gè)集群的大規(guī)模并行計(jì)算能力,快速返回查詢結(jié)果。

    更重要的是,多樣化的分片功能,為業(yè)務(wù)優(yōu)化打開了想象空間。比如在hash sharding的情況下,JOIN計(jì)算能夠避免數(shù)據(jù)shuffle,直接在本地進(jìn)行l(wèi)ocal join; 支持自定義sharding,可以為不同業(yè)務(wù)和SQL Pattern定制最適合的分片策略;利用自定義sharding功能,通過設(shè)置合理的sharding expression可以解決分片間數(shù)據(jù)傾斜問題等。

    ????????另外,sharding機(jī)制使得ClickHouse可以橫向線性拓展,構(gòu)建大規(guī)模分布式集群,從而具備處理海量數(shù)據(jù)的能力。

    Distributed 表引擎本身不存儲(chǔ)數(shù)據(jù),有點(diǎn)類似于 MyCat 之于 MySql,成為一種中間件,通過分布式邏輯表來寫入、分發(fā)、路由來操作多臺(tái)節(jié)點(diǎn)不同分片的分布式數(shù)據(jù)。

    注意:ClickHouse 的集群是表級(jí)別的,實(shí)際企業(yè)中,大部分做了高可用,但是沒有用分片,避免降低查詢性能以及操作集群的復(fù)雜性。

    集群寫入流程(3 分片 2 副本共 6 個(gè)節(jié)點(diǎn)):

    ?集群讀取流程(3 分片 2 副本共 6 個(gè)節(jié)點(diǎn)):

    hadoop202創(chuàng)建 Distribute 分布式表?

    create table st_order_mt_all on cluster gmall_cluster ( id UInt32, sku_id String, total_amount Decimal(16,2), create_time Datetime )engine = Distributed(gmall_cluster,default, st_order_mt,hiveHash(sku_id));--參數(shù)含義 Distributed(集群名稱,庫名,本地表名,分片鍵) 分片鍵必須是整型數(shù)字,所以用 hiveHash 函數(shù)轉(zhuǎn)換,也可以 rand()insert into st_order_mt_all values (201,'sku_001',1000.00,'2020-06-01 12:00:00') , (202,'sku_002',2000.00,'2020-06-01 12:00:00'), (203,'sku_004',2500.00,'2020-06-01 12:00:00'), (204,'sku_002',2000.00,'2020-06-01 12:00:00'), (205,'sku_003',600.00,'2020-06-02 12:00:00');--通過查詢分布式表和本地表觀察輸出結(jié)果 SELECT * FROM st_order_mt_all;

    st_order_mt_all?

    ?hadoop202: st_order_mt

    hadoop203:st_order_mt

    ?

    hadoop204:st_order_mt

    配置分片集群?vim /etc/clickhouse-server/config.d/metrika.xml

    六、數(shù)據(jù)分區(qū)?( partition by )Partition Key

    ? 作用
    學(xué)過 hive 的應(yīng)該都不陌生,分區(qū)的目的主要是降低掃描的范圍,優(yōu)化查詢速度
    ? ?如果不填
    只會(huì)使用一個(gè)分區(qū)。
    ? ?分區(qū)目錄
    MergeTree 是以列文件+索引文件+表定義文件組成的,但是如果設(shè)定了分區(qū)那么這
    些文件就會(huì)保存到不同的分區(qū)目錄中。
    ? ?并行
    分區(qū)后,面對(duì)涉及跨分區(qū)的查詢統(tǒng)計(jì),ClickHouse 會(huì)以分區(qū)為單位并行處理。
    ? ?數(shù)據(jù)寫入與分區(qū)合并
    任何一個(gè)批次的數(shù)據(jù)寫入都會(huì)產(chǎn)生一個(gè)臨時(shí)分區(qū),不會(huì)納入任何一個(gè)已有的分區(qū)。寫入
    后的某個(gè)時(shí)刻(大概 10-15 分鐘后),ClickHouse 會(huì)自動(dòng)執(zhí)行合并操作(等不及也可
    以手動(dòng)通過 optimize 執(zhí)行),把臨時(shí)分區(qū)的數(shù)據(jù),合并到已有分區(qū)中。
    optimize table xxxx final;

    ????????ClickHouse 將數(shù)據(jù)劃分為多個(gè) partition,每個(gè) partition 再進(jìn)一步劃分為多個(gè) index granularity,然后通過多個(gè) CPU 核心分別處理其中的一部分來實(shí)現(xiàn)并行數(shù)據(jù)處理。在這種設(shè)計(jì)下,單條 Query 就能利用整機(jī)所有 CPU。極致的并行處理能力,極大的降低了查詢延時(shí)。所以,ClickHouse 即使對(duì)于大量數(shù)據(jù)的查詢也能夠化整為零平行處理。但是有一個(gè)弊端就是對(duì)于單條查詢使用多 cpu,就不利于同時(shí)并發(fā)多條查詢。所以對(duì)于高 qps 的查詢業(yè)務(wù),ClickHouse 并不是強(qiáng)項(xiàng)。

    ????????ClickHouse支持PARTITION BY子句,在建表時(shí)可以指定按照任意合法表達(dá)式進(jìn)行數(shù)據(jù)分區(qū)操作,比如通過toYYYYMM()將數(shù)據(jù)按月進(jìn)行分區(qū)、toMonday()將數(shù)據(jù)按照周幾進(jìn)行分區(qū)、對(duì)Enum類型的列直接每種取值作為一個(gè)分區(qū)等。

    數(shù)據(jù)Partition在ClickHouse中主要有兩方面應(yīng)用:

    • 在partition key上進(jìn)行分區(qū)裁剪,只查詢必要的數(shù)據(jù)。靈活的partition expression設(shè)置,使得可以根據(jù)SQL Pattern進(jìn)行分區(qū)設(shè)置,最大化的貼合業(yè)務(wù)特點(diǎn)。
    • 對(duì)partition進(jìn)行TTL管理,淘汰過期的分區(qū)數(shù)據(jù)。
    create table t_order_mt( id UInt32, sku_id String, total_amount Decimal(16,2), create_time Datetime ) engine =MergeTree partition by toYYYYMMDD(create_time) primary key (id) order by (id,sku_id); insert into t_order_mt values (101,'sku_001',1000.00,'2020-06-01 12:00:00') , (102,'sku_002',2000.00,'2020-06-01 11:00:00'), (102,'sku_004',2500.00,'2020-06-01 12:00:00'), (102,'sku_002',2000.00,'2020-06-01 13:00:00'), (102,'sku_002',12000.00,'2020-06-01 13:00:00'), (102,'sku_002',600.00,'2020-06-02 12:00:00'); 再次執(zhí)行上面的插入操作 insert into t_order_mt values (101,'sku_001',1000.00,'2020-06-01 12:00:00') , (102,'sku_002',2000.00,'2020-06-01 11:00:00'), (102,'sku_004',2500.00,'2020-06-01 12:00:00'), (102,'sku_002',2000.00,'2020-06-01 13:00:00'), (102,'sku_002',12000.00,'2020-06-01 13:00:00'), (102,'sku_002',600.00,'2020-06-02 12:00:00');

    ClickHouse 中的主鍵primary key,和其他數(shù)據(jù)庫不太一樣,它只提供了數(shù)據(jù)的一級(jí)索引,但是卻
    不是唯一約束?

    ?

    ?手動(dòng) optimize 之后
    hadoop202 :) optimize table t_order_mt final;
    再次查詢 ,數(shù)據(jù)按照create_time進(jìn)行分區(qū)了

    ClickHouse 支持對(duì)數(shù)據(jù)分 Partition 存儲(chǔ),不同 Partition 之間的數(shù)據(jù)物理隔離,用戶可以根據(jù) Partition Key 快速過濾 Parition 是否有滿足條件的數(shù)據(jù),比如將數(shù)據(jù)按時(shí)間進(jìn)行分區(qū),不同月份的數(shù)據(jù)存儲(chǔ)到不同的 Partition,與傳統(tǒng)關(guān)系型數(shù)據(jù)庫的分區(qū)類似。

    例如 PARTIION BY score/10 相當(dāng)于按 score 進(jìn)行分區(qū),每10分一檔為一個(gè) Partion,當(dāng)查詢一檔內(nèi)的分?jǐn)?shù)區(qū)間時(shí),就可以快速過濾掉不相關(guān)的 Partition。

    七、主備同步,副本 寫入流程

    ????????ClickHouse通過主備復(fù)制提供了高可用能力,主備架構(gòu)下支持無縫升級(jí)等運(yùn)維操作。而且相比于其他系統(tǒng)它的實(shí)現(xiàn)有著自己的特色:

    • 1)默認(rèn)配置下,任何副本都處于active模式,可以對(duì)外提供查詢服務(wù);
    • 2)可以任意配置副本個(gè)數(shù),副本數(shù)量可以從0個(gè)到任意多個(gè);
    • 3)不同shard可以配置不提供副本個(gè)數(shù),用于解決單個(gè)shard的查詢熱點(diǎn)問題;

    副本 寫入流程?

    ?副本只能同步數(shù)據(jù),不能同步表結(jié)構(gòu),所以我們需要在每臺(tái)機(jī)器上自己手動(dòng)建表

    配置副本??vim /etc/clickhouse-server/config.d/metrika.xml

    <yandex><zookeeper-servers><node index="1"><host>hadoop202</host><port>2181</port></node><node index="2"><host>hadoop203</host><port>2181</port></node><node index="3"><host>hadoop204</host><port>2181</port></node></zookeeper-servers> </yandex>

    ?? ?在 hadoop202 的/etc/clickhouse-server/config.xml 中增加
    <include_from>/etc/clickhouse-server/config.d/metrika.xml</include_from>

    ? ?同步到 hadoop203 和 hadoop204 上

    sudo /home/atguigu/bin/xsync? /etc/clickhouse-server/config.d/metrika.xml
    sudo /home/atguigu/bin/xsync? /etc/clickhouse-server/config.xml

    分別在 hadoop202 和 hadoop203 上啟動(dòng) ClickHouse 服務(wù)?

    hadoop202

    create table t_order_rep ( id UInt32, sku_id String, total_amount Decimal(16,2), create_time Datetime ) engine =ReplicatedMergeTree('/clickhouse/tables/01/t_order_rep','rep_202') partition by toYYYYMMDD(create_time) primary key (id) order by (id,sku_id);

    hadoop203

    create table t_order_rep ( id UInt32, sku_id String, total_amount Decimal(16,2), create_time Datetime ) engine =ReplicatedMergeTree('/clickhouse/tables/01/t_order_rep','rep_203') partition by toYYYYMMDD(create_time) primary key (id) order by (id,sku_id);?

    在 hadoop202 上執(zhí)行 insert 語句

    insert into t_order_rep values (101,'sku_001',1000.00,'2020-06-01 12:00:00'), (102,'sku_002',2000.00,'2020-06-01 12:00:00'), (103,'sku_004',2500.00,'2020-06-01 12:00:00'), (104,'sku_002',2000.00,'2020-06-01 12:00:00'), (105,'sku_003',600.00,'2020-06-02 12:00:00');?

    在 hadoop203 上執(zhí)行 select,可以查詢出結(jié)果,說明副本配置正確

    八、高吞吐寫入能力LSM Tree

    ????????ClickHouse采用類LSM Tree的結(jié)構(gòu),數(shù)據(jù)寫入后定期在后臺(tái)Compaction。通過類LSM tree的結(jié)構(gòu),ClickHouse在數(shù)據(jù)導(dǎo)入時(shí)全部是順序append寫,寫入后數(shù)據(jù)段不可更改,在后臺(tái)compaction時(shí)也是多個(gè)段merge sort后順序?qū)懟卮疟P。順序?qū)懙奶匦?#xff0c;充分利用了磁盤的吞吐能力,即便在HDD上也有著優(yōu)異的寫入性能。

    ????????官方公開benchmark測試顯示能夠達(dá)到50MB-200MB/s的寫入吞吐能力,按照每行100Byte估算,大約相當(dāng)于50W-200W條/s的寫入速度。

    ????????ClickHouse采用列式作為單機(jī)存儲(chǔ),并且采用了類LSM tree的結(jié)構(gòu)來進(jìn)行組織與合并。一張MergeTree本地表,從磁盤文件構(gòu)成如下圖所示。

    ????????本地表的數(shù)據(jù)被劃分為多個(gè)Data PART,每個(gè)Data PART對(duì)應(yīng)一個(gè)磁盤目錄。Data PART在落盤后,就是immutable的,不再變化。ClickHouse后臺(tái)會(huì)調(diào)度MergerThread將多個(gè)小的Data PART不斷合并起來,形成更大的Data PART,從而獲得更高的壓縮率、更快的查詢速度。當(dāng)每次向本地表中進(jìn)行一次insert請(qǐng)求時(shí),就會(huì)產(chǎn)生一個(gè)新的Data PART,也即新增一個(gè)目錄。如果insert的batch size太小,且insert頻率很高,可能會(huì)導(dǎo)致目錄數(shù)過多進(jìn)而耗盡inode,也會(huì)降低后臺(tái)數(shù)據(jù)合并的性能,這也是為什么ClickHouse推薦使用大batch進(jìn)行寫入且每秒不超過1次的原因。

    ????????在Data PART內(nèi)部存儲(chǔ)著各個(gè)列的數(shù)據(jù),由于采用了列存格式,所以不同列使用完全獨(dú)立的物理文件。每個(gè)列至少有2個(gè)文件構(gòu)成,分別是.bin 和 .mrk文件其中.bin是數(shù)據(jù)文件,保存著實(shí)際的data;而.mrk是元數(shù)據(jù)文件,保存著數(shù)據(jù)的metadata。此外,ClickHouse還支持primary index、skip index等索引機(jī)制,所以也可能存在著對(duì)應(yīng)的pk.idx,skip_idx.idx文件

    數(shù)據(jù)寫入

    ????????在數(shù)據(jù)寫入過程中,數(shù)據(jù)被按照index_granularity切分為多個(gè)顆粒(granularity),默認(rèn)值為8192行對(duì)應(yīng)一個(gè)顆粒。多個(gè)顆粒在內(nèi)存buffer中積攢到了一定大小(由參數(shù)min_compress_block_size控制,默認(rèn)64KB),會(huì)觸發(fā)數(shù)據(jù)的壓縮、落盤等操作,形成一個(gè)block。每個(gè)顆粒會(huì)對(duì)應(yīng)一個(gè)mark,該mark主要存儲(chǔ)著2項(xiàng)信息:

    • 1)當(dāng)前block在壓縮后的物理文件中的offset,
    • 2)當(dāng)前granularity在解壓后block中的offset。

    所以Block是ClickHouse與磁盤進(jìn)行IO交互、壓縮/解壓縮的最小單位,而granularity是ClickHouse在內(nèi)存中進(jìn)行數(shù)據(jù)掃描的最小單位。

    ????????如果有ORDER BY key或Primary key,則ClickHouse在Block數(shù)據(jù)落盤前,會(huì)將數(shù)據(jù)按照ORDER BY key進(jìn)行排序。主鍵索引pk.idx中存儲(chǔ)著每個(gè)mark對(duì)應(yīng)的第一行數(shù)據(jù),也即在每個(gè)顆粒中各個(gè)列的最小值。

    當(dāng)存在其他類型的稀疏索引時(shí),會(huì)額外增加一個(gè)<col>_<type>.idx文件,用來記錄對(duì)應(yīng)顆粒的統(tǒng)計(jì)信息。比如:

    • minmax會(huì)記錄各個(gè)顆粒的最小、最大值;
    • set會(huì)記錄各個(gè)顆粒中的distinct值;
    • bloomfilter會(huì)使用近似算法記錄對(duì)應(yīng)顆粒中,某個(gè)值是否存在;

    ?ClickHouse寫入鏈路

    ClickHouse提供2種寫入方法,1)寫本地表;2)寫分布式表。

    ????????寫本地表方式,需要業(yè)務(wù)層感知底層所有server的IP,并且自行處理數(shù)據(jù)的分片操作。由于每個(gè)節(jié)點(diǎn)都可以分別直接寫入,這種方式使得集群的整體寫入能力與節(jié)點(diǎn)數(shù)完全成正比,提供了非常高的吞吐能力和定制靈活性。但是相對(duì)而言,也增加了業(yè)務(wù)層的依賴,引入了更多復(fù)雜性,尤其是節(jié)點(diǎn)failover容錯(cuò)處理、擴(kuò)縮容數(shù)據(jù)re-balance、寫入和查詢需要分別使用不同表引擎等都要在業(yè)務(wù)上自行處理。

    ????????而寫分布式表則相對(duì)簡單,業(yè)務(wù)層只需要將數(shù)據(jù)寫入單一endpoint及單一一張分布式表即可,不需要感知底層server拓?fù)浣Y(jié)構(gòu)等實(shí)現(xiàn)細(xì)節(jié)。寫分布式表也有很好的性能表現(xiàn),在不需要極高寫入吞吐能力的業(yè)務(wù)場景中,建議直接寫入分布式表降低業(yè)務(wù)復(fù)雜度。

    以下闡述分布式表的寫入實(shí)現(xiàn)原理。

    ClickHouse使用Block作為數(shù)據(jù)處理的核心抽象,表示在內(nèi)存中的多個(gè)列的數(shù)據(jù),其中列的數(shù)據(jù)在內(nèi)存中也采用列存格式進(jìn)行存儲(chǔ)。示意圖如下:其中header部分包含block相關(guān)元信息,而id UInt8、name String、_date Date則是三個(gè)不同類型列的數(shù)據(jù)表示。

    ?在Block之上,封裝了能夠進(jìn)行流式IO的stream接口,分別是IBlockInputStream、IBlockOutputStream,接口的不同對(duì)應(yīng)實(shí)現(xiàn)不同功能。

    當(dāng)收到INSERT INTO請(qǐng)求時(shí),ClickHouse會(huì)構(gòu)造一個(gè)完整的stream pipeline,每一個(gè)stream實(shí)現(xiàn)相應(yīng)的邏輯:

    InputStreamFromASTInsertQuery #將insert into請(qǐng)求封裝為InputStream作為數(shù)據(jù)源 -> CountingBlockOutputStream #統(tǒng)計(jì)寫入block count -> SquashingBlockOutputStream #積攢寫入block,直到達(dá)到特定內(nèi)存閾值,提升寫入吞吐 -> AddingDefaultBlockOutputStream #用default值補(bǔ)全缺失列 -> CheckConstraintsBlockOutputStream #檢查各種限制約束是否滿足 -> PushingToViewsBlockOutputStream #如有物化視圖,則將數(shù)據(jù)寫入到物化視圖中 -> DistributedBlockOutputStream #將block寫入到分布式表中

    在以上過程中,ClickHouse非常注重細(xì)節(jié)優(yōu)化,處處為性能考慮。在SQL解析時(shí),ClickHouse并不會(huì)一次性將完整的INSERT INTO table(cols) values(rows)解析完畢,而是先讀取insert into table(cols)這些短小的頭部信息來構(gòu)建block結(jié)構(gòu),values部分的大量數(shù)據(jù)則采用流式解析,降低內(nèi)存開銷。在多個(gè)stream之間傳遞block時(shí),實(shí)現(xiàn)了copy-on-write機(jī)制,盡最大可能減少內(nèi)存拷貝。在內(nèi)存中采用列存存儲(chǔ)結(jié)構(gòu),為后續(xù)在磁盤上直接落盤為列存格式做好準(zhǔn)備。

    SquashingBlockOutputStream將客戶端的若干小寫,轉(zhuǎn)化為大batch,提升寫盤吞吐、降低寫入放大、加速數(shù)據(jù)Compaction。

    默認(rèn)情況下,分布式表寫入是異步轉(zhuǎn)發(fā)的。
    DistributedBlockOutputStream將Block按照建表DDL中指定的規(guī)則(如hash或random)切分為多個(gè)分片,每個(gè)分片對(duì)應(yīng)本地的一個(gè)子目錄,將對(duì)應(yīng)數(shù)據(jù)落盤為子目錄下的.bin文件,寫入完成后就返回client成功。隨后分布式表的后臺(tái)線程,掃描這些文件夾并將.bin文件推送給相應(yīng)的分片server。.bin文件的存儲(chǔ)格式示意如下:

    數(shù)據(jù)查詢? ? ? ??

    ????????在查找時(shí),如果query包含主鍵索引條件,則首先在pk.idx中進(jìn)行二分查找,找到符合條件的顆粒mark,并從mark文件中獲取block offset、granularity offset等元數(shù)據(jù)信息,進(jìn)而將數(shù)據(jù)從磁盤讀入內(nèi)存進(jìn)行查找操作。類似的,如果條件命中skip index,則借助于index中的minmax、set等信息,定位出符合條件的顆粒mark,進(jìn)而執(zhí)行IO操作。借助于mark文件,ClickHouse在定位出符合條件的顆粒之后,可以將顆粒平均分派給多個(gè)線程進(jìn)行并行處理,最大化利用磁盤的IO吞吐和CPU的多核處理能力。

    二、ClickHouse計(jì)算層

    ????????ClickHouse在計(jì)算層做了非常細(xì)致的工作,竭盡所能榨干硬件能力,提升查詢速度。它實(shí)現(xiàn)了單機(jī)多核并行、分布式計(jì)算、向量化執(zhí)行與SIMD指令、代碼生成等多種重要技術(shù)。

    1、多核并行

    ????????ClickHouse將數(shù)據(jù)劃分為多個(gè)partition,每個(gè)partition再進(jìn)一步劃分為多個(gè)index granularity,然后通過多個(gè)CPU核心分別處理其中的一部分來實(shí)現(xiàn)并行數(shù)據(jù)處理

    在這種設(shè)計(jì)下,單條Query就能利用整機(jī)所有CPU。極致的并行處理能力,極大的降低了查詢延時(shí)。

    2、分布式計(jì)算

    ????????除了優(yōu)秀的單機(jī)并行處理能力,ClickHouse還提供了可線性拓展的分布式計(jì)算能力。ClickHouse會(huì)自動(dòng)將查詢拆解為多個(gè)task下發(fā)到集群中,然后進(jìn)行多機(jī)并行處理,最后把結(jié)果匯聚到一起。

    在存在多副本的情況下,ClickHouse提供了多種query下發(fā)策略:

    • 隨機(jī)下發(fā):在多個(gè)replica中隨機(jī)選擇一個(gè);
    • 最近hostname原則:選擇與當(dāng)前下發(fā)機(jī)器最相近的hostname節(jié)點(diǎn),進(jìn)行query下發(fā)。在特定的網(wǎng)絡(luò)拓?fù)湎?#xff0c;可以降低網(wǎng)絡(luò)延時(shí)。而且能夠確保query下發(fā)到固定的replica機(jī)器,充分利用系統(tǒng)cache。
    • in order:按照特定順序逐個(gè)嘗試下發(fā),當(dāng)前一個(gè)replica不可用時(shí),順延到下一個(gè)replica。
    • first or random:在In Order模式下,當(dāng)?shù)谝粋€(gè)replica不可用時(shí),所有workload都會(huì)積壓到第二個(gè)Replica,導(dǎo)致負(fù)載不均衡。first or random解決了這個(gè)問題:當(dāng)?shù)谝粋€(gè)replica不可用時(shí),隨機(jī)選擇一個(gè)其他replica,從而保證其余replica間負(fù)載均衡。另外在跨region復(fù)制場景下,通過設(shè)置第一個(gè)replica為本region內(nèi)的副本,可以顯著降低網(wǎng)絡(luò)延時(shí)。

    3、向量化執(zhí)行與SIMD

    ????????ClickHouse不僅將數(shù)據(jù)按列存儲(chǔ),而且按列進(jìn)行計(jì)算。傳統(tǒng)OLTP數(shù)據(jù)庫通常采用按行計(jì)算,原因是事務(wù)處理中以點(diǎn)查為主,SQL計(jì)算量小,實(shí)現(xiàn)這些技術(shù)的收益不夠明顯。但是在分析場景下,單個(gè)SQL所涉及計(jì)算量可能極大,將每行作為一個(gè)基本單元進(jìn)行處理會(huì)帶來嚴(yán)重的性能損耗:

    • 1)對(duì)每一行數(shù)據(jù)都要調(diào)用相應(yīng)的函數(shù),函數(shù)調(diào)用開銷占比高;
    • 2)存儲(chǔ)層按列存儲(chǔ)數(shù)據(jù),在內(nèi)存中也按列組織,但是計(jì)算層按行處理,無法充分利用CPU cache的預(yù)讀能力,造成CPU Cache miss嚴(yán)重;
    • 3)按行處理,無法利用高效的SIMD指令;

    ????????ClickHouse實(shí)現(xiàn)了向量執(zhí)行引擎(Vectorized execution engine),對(duì)內(nèi)存中的列式數(shù)據(jù),一個(gè)batch調(diào)用一次SIMD指令(而非每一行調(diào)用一次),不僅減少了函數(shù)調(diào)用次數(shù)、降低了cache miss,而且可以充分發(fā)揮SIMD指令的并行能力,大幅縮短了計(jì)算耗時(shí)。向量執(zhí)行引擎,通常能夠帶來數(shù)倍的性能提升。

    4、動(dòng)態(tài)代碼生成Runtime Codegen

    ????????在經(jīng)典的數(shù)據(jù)庫實(shí)現(xiàn)中,通常對(duì)表達(dá)式計(jì)算采用火山模型,也即將查詢轉(zhuǎn)換成一個(gè)個(gè)operator,比如HashJoin、Scan、IndexScan、Aggregation等。為了連接不同算子,operator之間采用統(tǒng)一的接口,比如open/next/close。在每個(gè)算子內(nèi)部都實(shí)現(xiàn)了父類的這些虛函數(shù),在分析場景中單條SQL要處理數(shù)據(jù)通常高達(dá)數(shù)億行,虛函數(shù)的調(diào)用開銷不再可以忽略不計(jì)。另外,在每個(gè)算子內(nèi)部都要考慮多種變量,比如列類型、列的size、列的個(gè)數(shù)等,存在著大量的if-else分支判斷導(dǎo)致CPU分支預(yù)測失效。

    ClickHouse實(shí)現(xiàn)了Expression級(jí)別的runtime codegen,動(dòng)態(tài)地根據(jù)當(dāng)前SQL直接生成代碼,然后編譯執(zhí)行。如下圖例子所示,對(duì)于Expression直接生成代碼,不僅消除了大量的虛函數(shù)調(diào)用(即圖中多個(gè)function pointer的調(diào)用),而且由于在運(yùn)行時(shí)表達(dá)式的參數(shù)類型、個(gè)數(shù)等都是已知的,也消除了不必要的if-else分支判斷。

    5、近似計(jì)算

    ????????近似計(jì)算以損失一定結(jié)果精度為代價(jià),極大地提升查詢性能。在海量數(shù)據(jù)處理中,近似計(jì)算價(jià)值更加明顯。

    ClickHouse實(shí)現(xiàn)了多種近似計(jì)算功能:

    • 近似估算distinct values、中位數(shù),分位數(shù)等多種聚合函數(shù);
    • 建表DDL支持SAMPLE BY子句,支持對(duì)于數(shù)據(jù)進(jìn)行抽樣處理;

    6、復(fù)雜數(shù)據(jù)類型支持

    ClickHouse還提供了array、json、tuple、set等復(fù)合數(shù)據(jù)類型,支持業(yè)務(wù)schema的靈活變更。

    查詢加速

  • 如果表指定了 Partition Key,并且查詢條件包含 Partition Key,則根據(jù)查詢條件快速過濾滿足條件的 Partition。
  • 在 Partition 內(nèi)部,如果查詢條件指定了 Primary Key 或 Sort Key,則根據(jù) Primary Index 來過濾滿足條件的索引單元。
  • 如果查詢條件的列有 Skip Index,則根據(jù)對(duì)應(yīng) Index 過濾滿足條件的索引單元。
  • 三、Clickhouse為什么這么快?減少數(shù)據(jù)掃描范圍

    ????????相信看過ClickHouse性能測試報(bào)告的同學(xué)都很震驚于他超高的OLAP查詢性能。于是下一步開始搜索“ClickHouse性能為什么高”看到了例如:

    1 計(jì)算

    • 多核并行
    • 分布式計(jì)算
    • 向量化執(zhí)行
    • 基于內(nèi)存

    2 存儲(chǔ)

    • 列式存儲(chǔ)
    • 數(shù)據(jù)壓縮
    • 有序
    • 稀疏索引
    • 數(shù)據(jù)分片
    • 分區(qū)
    • 主備?

    針對(duì)OLAP類的查詢最簡單的優(yōu)化方式就是減少數(shù)據(jù)掃描范圍,故而我們以此作為開篇。

    問題:
    有一個(gè)表(tab01)有10個(gè)int類型的字段(col1,col2,col3…col10),這個(gè)表中有十億條數(shù)據(jù)。
    {176, 35, 27, 82, 65, 75, 20, 25, 92, 35},
    {322, 42, 33, 12, 82, 77, 65, 22, 98, 12},

    為了簡單假定該表沒有主鍵和索引,在本篇中也不考慮任何的數(shù)據(jù)壓縮。

    需要完成如下查詢:

    SELECT avg(col1),avg(col2) FROM tab01 WHERE col3 > 500;

    方案一:行存儲(chǔ)

    ????????傳統(tǒng)的 MySQL 數(shù)據(jù)庫的每一行數(shù)據(jù)都是物理的存儲(chǔ)在一起的。如果我要去 id 等于 10000 這一條數(shù)據(jù)的 name 列,那我就必須要把這一行數(shù)據(jù)讀取出來,然后取 name 列。由于 name 列的數(shù)據(jù)都存儲(chǔ)在一起,因此效率大大地超過了傳統(tǒng)的數(shù)據(jù)庫。

    ????????如果該表以行存儲(chǔ)的方式存儲(chǔ)為一個(gè)文件:tab01.dat , 每條數(shù)據(jù)40字節(jié),那么整個(gè)文件大小為40GB,在這個(gè)方案中,我們需要從頭到尾讀取文件所有數(shù)據(jù),也就是需要從磁盤讀取40GB的內(nèi)容。顯然行存儲(chǔ)方案對(duì)于處理這類問題來說并不高效。

    列存儲(chǔ)

    ????????如果我們將該表的數(shù)據(jù)以列存儲(chǔ),即:將所有數(shù)據(jù)存儲(chǔ)為10個(gè)文件,col1.dat 存儲(chǔ)col1列所有的10億條數(shù)據(jù),依此類推,我們得到了10個(gè)數(shù)據(jù)文件,每個(gè)數(shù)據(jù)文件存儲(chǔ)十億個(gè)數(shù)據(jù),大小為4GB。
    ????????那么完成上面的查詢,只需要讀取col1.dat 、 col2.dat 、 col3.dat 三個(gè)文件,總共12GB。 讀磁盤的大小僅為方案一的30%。 現(xiàn)在我們就通過減少數(shù)據(jù)掃描范圍達(dá)到了提升性能的目的。這也是列存儲(chǔ)廣泛應(yīng)用在OLAP場景中的原因。

    方案二:高效的數(shù)據(jù)壓縮,默認(rèn)使用LZ4算法,總體壓縮比可達(dá) 8:1。

    ????????默認(rèn)使用LZ4算法壓縮,在Yandex.Metrica的生產(chǎn)環(huán)境中,數(shù)據(jù)總體的壓縮比可以達(dá)到8:1 ( 未壓縮前17PB,壓縮后2PB )。列式存儲(chǔ)除了降低IO和存儲(chǔ)的壓力之外,還為向量化執(zhí)行做好了鋪墊。

    按列存儲(chǔ)相比按行存儲(chǔ)的另一個(gè)優(yōu)勢是對(duì)數(shù)據(jù)壓縮的友好性。同樣可以用一個(gè)示例簡單說明壓縮的本質(zhì)是什么。假設(shè)有兩個(gè)字符串a(chǎn)bcdefghi和bcdefghi,現(xiàn)在對(duì)它們進(jìn)行壓縮,如下所示:

    壓縮前:abcdefghi_bcdefghi壓縮后:abcdefghi_(9,8)
    可以看到,壓縮的本質(zhì)是按照一定步長對(duì)數(shù)據(jù)進(jìn)行匹配掃描,當(dāng)發(fā)現(xiàn)重復(fù)部分的時(shí)候就進(jìn)行編碼轉(zhuǎn)換。例如上述示例中的 (9,8),表示如果從下劃線開始向前移動(dòng)9個(gè)字節(jié),會(huì)匹配到8個(gè)字節(jié)長度的重復(fù)項(xiàng),即這里的bcdefghi。

    方案三: 將數(shù)據(jù)分塊

    借助分布式表,能夠代理訪問多個(gè)數(shù)據(jù)分片,從而實(shí)現(xiàn)分布式查詢。

    在列存儲(chǔ)的基礎(chǔ)上,如果按照8192條數(shù)據(jù)進(jìn)行分塊,比如:col1.dat 的前 8192條數(shù)據(jù)是數(shù)據(jù)塊1,接下來8192條數(shù)據(jù)是數(shù)據(jù)塊2。所有數(shù)據(jù)文件都是如此,數(shù)據(jù)的邏輯組織如下所示:

    ?數(shù)據(jù)列分塊示意圖

    執(zhí)行過程:以數(shù)據(jù)塊為單位依次讀取col3列的所有數(shù)據(jù)塊,取得數(shù)據(jù)塊中所有符合條件(col3 > 500)的數(shù)據(jù)下標(biāo)。

    如果在該數(shù)據(jù)塊中有符合條件的數(shù)據(jù),則從col1.dat和col2.dat中讀取對(duì)應(yīng)位置的數(shù)據(jù)塊,并取出對(duì)應(yīng)位置的數(shù)據(jù)。
    如果在該數(shù)據(jù)塊中沒有符合條件的數(shù)據(jù),則不需要讀取col1.dat和col2.dat中對(duì)應(yīng)位置的數(shù)據(jù)塊。
    在這個(gè)優(yōu)化中,我們只需要讀取col3.dat全部數(shù)據(jù)和部分或全部col1.dat和col2.dat的數(shù)據(jù),數(shù)據(jù)掃描范圍相比于上一個(gè)方案進(jìn)一步縮小。 這也就是ClickHouse中PreWhere所作的優(yōu)化。

    方案四: 數(shù)據(jù)塊索引

    ????????一般的OLAP可能需要存儲(chǔ)千億甚至萬億級(jí)的數(shù)據(jù),普通一條數(shù)據(jù)一個(gè)索引的方式已經(jīng)不適應(yīng)于這么大的數(shù)據(jù)量。此時(shí),對(duì)數(shù)據(jù)列上以數(shù)據(jù)塊為單位建立索引是比較適合的方案。例如:對(duì)上例中列col3以數(shù)據(jù)塊建立索引每條索引存儲(chǔ)指定數(shù)據(jù)塊中的最大值、最小值,十億條數(shù)據(jù)的列僅需要不到13萬條索引。

    數(shù)據(jù)塊索引

    執(zhí)行過程:首先讀取col3數(shù)據(jù)塊索引,判斷該列存儲(chǔ)的數(shù)據(jù)是否滿足條件[27,87] 與 (500,) 是否有交集。

    如果有交集則繼續(xù)上一個(gè)方案的步驟。
    如果沒有交集則不需要讀取任何數(shù)據(jù)塊。
    在這個(gè)優(yōu)化中,需要讀取col3.idx所有的數(shù)據(jù),以及col1, col2, col3 的部分?jǐn)?shù)據(jù)塊。與上一個(gè)方案相比,掃描到的數(shù)據(jù)量進(jìn)一步縮小。

    一說到Clickhouse,大家都知道它非常快,那么CH為什么這么快,是因?yàn)槭褂昧讼蛄炕⒘惺綌?shù)據(jù)庫還是其它。下面我們一起來探索它的奧秘。(《ClickHouse原理解析與應(yīng)用實(shí)踐》總結(jié))

    1、硬件方面

    ????????ClickHouse會(huì)在內(nèi)存中進(jìn)行GROUP BY,并且使用HashTable裝載數(shù)據(jù)。與此同時(shí),他們非常在意CPU L3級(jí)別的緩存,因?yàn)橐淮蜭3的緩存失效會(huì)帶來70~100ns的延遲。這意味著在單核CPU上,它會(huì)浪費(fèi)4000萬次/秒的運(yùn)算;而在一個(gè)32線程的CPU上,則可能會(huì)浪費(fèi)5億次/秒的運(yùn)算。所以別小看這些細(xì)節(jié),一點(diǎn)一滴地將它們累加起來,數(shù)據(jù)是非常可觀的。正因?yàn)樽⒁饬诉@些細(xì)節(jié),所以ClickHouse在基準(zhǔn)查詢中能做到1.75億次/秒的數(shù)據(jù)掃描性能。

    2、算法方面

    ????????在ClickHouse的底層實(shí)現(xiàn)中,經(jīng)常會(huì)面對(duì)一些重復(fù)的場景,例如字符串子串查詢、數(shù)組排序、使用HashTable等。如何才能實(shí)現(xiàn)性能的最大化呢?算法的選擇是重中之重。以字符串為例,有一本專門講解字符串搜索的書,名為'Handbook of Exact String Matching Algorithms',列舉了35種常見的字符串搜索算法。各位猜一猜ClickHouse使用了其中的哪一種?答案是一種都沒有。這是為什么呢?因?yàn)樾阅懿粔蚩臁T谧址阉鞣矫?#xff0c;針對(duì)不同的場景,ClickHouse最終選擇了這些算法

    • 對(duì)于常量,使用Volnitsky算法;
    • 對(duì)于非常量,使用CPU的向量化執(zhí)行SIMD,暴力優(yōu)化;
    • 正則匹配使用re2和hyperscan算法。

    性能是算法選擇的首要考量指標(biāo)。

    3、應(yīng)景優(yōu)化,特定場景,特殊優(yōu)化

    CH會(huì)在不同的場景使用不同的算法。例如,在去重函數(shù)uniqCombined中,會(huì)根據(jù)數(shù)據(jù)量選擇不同的算法:數(shù)據(jù)量比較少的時(shí)候,會(huì)選擇使用Array來保存;數(shù)據(jù)量中等的時(shí)候,使用HashSet;數(shù)據(jù)量很大的時(shí)候,會(huì)使用HyperLogLog算法。

    針對(duì)同一個(gè)場景的不同狀況,選擇使用不同的實(shí)現(xiàn)方式,盡可能將性能最大化。關(guān)于這一點(diǎn),其實(shí)在前面介紹字符串查詢時(shí),針對(duì)不同場景選擇不同算法的思路就有體現(xiàn)了。類似的例子還有很多,例如去重計(jì)數(shù)uniqCombined函數(shù),會(huì)根據(jù)數(shù)據(jù)量的不同選擇不同的算法:

    • 當(dāng)數(shù)據(jù)量較小的時(shí)候,會(huì)選擇Array保存;
    • 當(dāng)數(shù)據(jù)量中等的時(shí)候,會(huì)選擇HashSet;
    • 而當(dāng)數(shù)據(jù)量很大的時(shí)候,則使用HyperLogLog算法。

    對(duì)于數(shù)據(jù)結(jié)構(gòu)比較清晰的場景,會(huì)通過代碼生成技術(shù)實(shí)現(xiàn)循環(huán)展開,以減少循環(huán)次數(shù)。接著就是大家熟知的大殺器—向量化執(zhí)行了。SIMD被廣泛地應(yīng)用于文本轉(zhuǎn)換、數(shù)據(jù)過濾、數(shù)據(jù)解壓和JSON轉(zhuǎn)換等場景。相較于單純地使用CPU,利用寄存器暴力優(yōu)化也算是一種降維打擊了。

    5.?多樣化的表引擎

    也許因?yàn)閅andex.Metrica的最初架構(gòu)是基于MySQL實(shí)現(xiàn)的,所以在ClickHouse的設(shè)計(jì)中,能夠察覺到一些MySQL的影子,表引擎的設(shè)計(jì)就是其中之一。與MySQL類似,ClickHouse也將存儲(chǔ)部分進(jìn)行了抽象,把存儲(chǔ)引擎作為一層獨(dú)立的接口。截至本書完稿時(shí),ClickHouse共擁有合并樹、內(nèi)存、文件、接口和其他6大類20多種表引擎。其中每一種表引擎都有著各自的特點(diǎn),用戶可以根據(jù)實(shí)際業(yè)務(wù)場景的要求,選擇合適的表引擎使用。

    將表引擎獨(dú)立設(shè)計(jì)的好處是顯而易見的,通過特定的表引擎支撐特定的場景,十分靈活。對(duì)于簡單的場景,可直接使用簡單的引擎降低成本,而復(fù)雜的場景也有合適的選擇。

    4、向量化、多線程與分布式

    坊間有句玩笑,即'能用錢解決的問題,千萬別花時(shí)間'。而業(yè)界也有種調(diào)侃如出一轍,即'能升級(jí)硬件解決的問題,千萬別優(yōu)化程序'。有時(shí)候,你千辛萬苦優(yōu)化程序邏輯帶來的性能提升,還不如直接升級(jí)硬件來得簡單直接。

    ?距離CPU越遠(yuǎn),則數(shù)據(jù)的訪問速度越慢。從寄存器中訪問數(shù)據(jù)的速度,是從內(nèi)存訪問數(shù)據(jù)速度的300倍,是從磁盤中訪問數(shù)據(jù)速度的3000萬倍。所以利用CPU向量化執(zhí)行的特性,對(duì)于程序的性能提升意義非凡。

    SIMD的全稱是Single Instruction Multiple Data,即用單條指令操作多條數(shù)據(jù)。現(xiàn)代計(jì)算機(jī)系統(tǒng)概念中,它是通過數(shù)據(jù)并行以提高性能的一種實(shí)現(xiàn)方式 ( 其他的還有指令級(jí)并行和線程級(jí)并行 ),它的原理是在CPU寄存器層面實(shí)現(xiàn)數(shù)據(jù)的并行操作。,CH使用向量化執(zhí)行。SIMD被廣泛地應(yīng)用于文本轉(zhuǎn)換、數(shù)據(jù)過濾、數(shù)據(jù)解壓和JSON轉(zhuǎn)換等場景。相對(duì)于單純使用CPU,利用寄存器暴力優(yōu)化也算是一種降維打擊

    5、持續(xù)測試和持續(xù)改進(jìn)

    如果只是單純地在上述細(xì)節(jié)上下功夫,還不足以構(gòu)建出如此強(qiáng)大的ClickHouse,還需要擁有一個(gè)能夠持續(xù)驗(yàn)證、持續(xù)改進(jìn)的機(jī)制。由于Yandex的天然優(yōu)勢,ClickHouse經(jīng)常會(huì)使用真實(shí)的數(shù)據(jù)進(jìn)行測試,這一點(diǎn)很好地保證了測試場景的真實(shí)性。與此同時(shí),ClickHouse也是我見過的發(fā)版速度最快的開源軟件了,差不多每個(gè)月都能發(fā)布一個(gè)版本。沒有一個(gè)可靠的持續(xù)集成環(huán)境,這一點(diǎn)是做不到的。正因?yàn)閾碛羞@樣的發(fā)版頻率,ClickHouse才能夠快速迭代、快速改進(jìn)。

    四、哪些場景比較適合使用ClickHouse呢?

    ????????ClickHouse比較適合分析結(jié)構(gòu)化的、干凈的、不可變的流式數(shù)據(jù),比如打點(diǎn)日志分析啦,行為分析啦。強(qiáng)烈建議將源源不斷的流式數(shù)據(jù)和提前已經(jīng)定義好的維度表組合起來,并塞到一個(gè)基于事實(shí)的大寬表中去( a single wide fact table,一張寬大的事實(shí)表,是不是很有親切感?)。

    ClickHouse比較適用于以下行業(yè)/場景:

    • 網(wǎng)頁端和客戶端產(chǎn)品的數(shù)據(jù)分析
    • 廣告系統(tǒng)和實(shí)時(shí)競價(jià)廣告
    • 電信行業(yè)
    • 電商和金融行業(yè)
    • 信息安全
    • 實(shí)時(shí)監(jiān)控和遙感測量
    • 時(shí)間序列
    • 商業(yè)智能
    • 在線游戲
    • 所有的互聯(lián)網(wǎng)場景

    ClickHouse不適合的場景:

    • OLAP聯(lián)機(jī)事物處理(上面提到過的,小黑板敲起來,mysql這種比較適合)
    • 鍵值對(duì)數(shù)據(jù)高效率訪問請(qǐng)求(想到redis了嘛?)
    • 二進(jìn)制數(shù)據(jù)或文件存儲(chǔ)(想到mongDB了嘛?)
    • 過度標(biāo)準(zhǔn)化的數(shù)據(jù)(有很多人好奇了,開什么玩笑,數(shù)據(jù)按說應(yīng)該是越標(biāo)準(zhǔn)化越好啊?這個(gè)問題應(yīng)該這樣理解,那些過于簡單直接、沒啥維度和靈活度需求的數(shù)據(jù),咋能體現(xiàn)ClickHouse的優(yōu)勢呢,你用啥數(shù)據(jù)庫都能做得很6啊)

    五、 clickhouse與mysql查詢速度對(duì)比

    數(shù)據(jù)量為308萬行,每行14個(gè)列的測試

    select * from bigtable

    clickhouse:67.62s?? ;??? mysql:0.002s

    ?? clickhouse感覺是瞬間查出來,但是加載10000行數(shù)據(jù)刷屏用了很久很久,clickhouse里查詢的列數(shù)一多,加載的時(shí)間就變長

    • TOPN select* from bigtable order by dish_Name limit 1 clickhouse:0.13s?? ;??? mysql:0.020s
    • 統(tǒng)計(jì)數(shù)據(jù)有多少行:
    select count(1) from bigtable

    ????clickhouse:0.015s?? ;??? mysql:1.33s

    • 統(tǒng)計(jì)一共有多少個(gè)訂單:
    select count(1) from (select consumption_id,created_org from bigtable group by consumption_id,created_org)a;

    ????clickhouse:0.121s?? ;??? mysql:5.15s

    • 來吃過的次數(shù)里各有多少人:82行
    select sum_all,count(1) as countall from (select member_id,count(1) as sum_all from (select member_id,consumption_id,created_org from bigtable group by consumption_id,created_org) a group by member_id) a group by sum_all;

    ????clickhouse:0.166s?? ;??? mysql:5.50s

    • 添加條件的查詢:
    SELECT COUNT(1) FROM bigtable WHERE member_id IN (1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19, 20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39, 40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59, 60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75, 76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94, 95,96,97,98,99,100) AND bill_date BETWEEN '2017-01-01' AND '2017-12-31' AND fans_id >10

    ?????clickhouse:0.027s?? ;??? mysql:2.05s

    • 每個(gè)用戶最常吃的菜品:8萬行
    SELECT member_id,dish_name,sum_all FROM ( SELECT member_id,dish_name,COUNT(1) AS sum_all FROM bigtable WHERE dish_name NOT IN('米飯','打包盒','茶位費(fèi)') GROUP BY member_id,dish_name ORDER BY member_id,sum_all DESC) a GROUP BY member_id

    clickhouse:11.90s ; mysql:9.88s

    • 來個(gè)猛的,四重子查詢:171萬行
    SELECT * FROM bigtable WHERE member_id IN(SELECT member_id FROM bigtable WHERE member_id IN(SELECT member_id FROM bigtable WHERE source_type=1 AND member_id IN (SELECT member_id FROM bigtable WHERE source_type=1 AND member_id IN (SELECT member_id FROM bigtable WHERE fans_id !=0)) ) AND is_subscribed=1 )

    clickhouse:65.284s ; mysql:Mysql不行了,查了30分鐘還沒結(jié)果;clickhouse同樣是加載行數(shù)用了很久

    關(guān)聯(lián)表查詢,三個(gè)表分別為近100萬,13萬,13萬:?三個(gè)表相互關(guān)聯(lián)拼接的查詢: 8萬行

    clickhouse:3.65s ; mysql:4min46s

    在幾萬十幾萬行的數(shù)據(jù)里,clickhouse的速度也是要顯著快于mysql

    結(jié)論:

    那么這部分對(duì)比查詢時(shí)間的結(jié)果顯而易見了:

    • ????對(duì)于簡單查詢來說,查詢列數(shù)多的話mysql有優(yōu)勢,查詢列數(shù)少的話clickhouse領(lǐng)先
    • ??? 對(duì)于復(fù)雜查詢來說,clickhouse占有顯著優(yōu)勢

    另外,展示行數(shù)的多少會(huì)影響clickhouse的查詢時(shí)間,不知道是不是因?yàn)槭褂胠inux的原因

    ClickHouse 對(duì)比 Greenplum?

    從測試結(jié)果看,ClickHouse 幾乎在所有場景下性能都最佳,并且從所有查詢整體看,ClickHouse 領(lǐng)先圖靈獎(jiǎng)得主 Michael Stonebraker 所創(chuàng)建的 Vertica 達(dá) 6 倍,領(lǐng)先 Greenplum 達(dá)到 18 倍。?

    總結(jié)

    以上是生活随笔為你收集整理的OLAP(四):ClickHouse的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。