clickhouse使用入門(clickhouse使用教程)

導(dǎo)語(yǔ):同學(xué),你也不想你根本不懂ClickHouse,卻趕鴨子上架使用的事情被其他人知道吧?

寫在前面:本文旨在讓原先有一定SQL基礎(chǔ)的人快速簡(jiǎn)單了解ClickHouse的(關(guān)鍵)概念/特性,側(cè)重于使用方面的介紹比較而非原理/實(shí)現(xiàn)挖掘。文章算是個(gè)人摘錄學(xué)習(xí) 理解,主要參考資料為ClickHouse官方(英文)文檔(畢竟絕對(duì)權(quán)威),寫于2023年5月,請(qǐng)注意時(shí)效性。

簡(jiǎn)要介紹

ClickHouse是一個(gè)用于聯(lián)機(jī)分析處理(OLAP)的列式數(shù)據(jù)庫(kù)管理系統(tǒng)(DBMS),擁有著及其卓越的查詢速度。OLAP是一種面向分析的處理,用于處理大量的數(shù)據(jù)并支持復(fù)雜的分析和查詢操作。諸如BI系統(tǒng)等重?cái)?shù)據(jù)分析的場(chǎng)景,都應(yīng)重點(diǎn)考慮使用OLAP數(shù)據(jù)庫(kù),而其中ClickHouse又是OLAP數(shù)據(jù)庫(kù)星海中最璀璨的一顆星。

ClickHouse的場(chǎng)景特點(diǎn)

縱使ClickHouse有千般萬(wàn)好,但是能真正契合系統(tǒng)需求的數(shù)據(jù)庫(kù),才是最合適的。因此,在我們正式邁進(jìn)ClickHouse使用大門之前,我想有必要先識(shí)其長(zhǎng)短。

clickhouse使用入門(clickhouse使用教程)

上圖截自ClickHouse官方文檔,與其說(shuō)這是olap的場(chǎng)景,不妨說(shuō)是ClickHouse的常見(jiàn)場(chǎng)景。其中我覺(jué)得有必要指出的是:

1.”查詢相對(duì)較少”,這意味著ClickHouse并發(fā)查詢能力不強(qiáng)(官方建議每秒最多查詢100次),原因在于對(duì)于每條查詢,ClickHouse都會(huì)盡可能動(dòng)用服務(wù)器的CPU、內(nèi)存資源等,而不同于MySQL單條SQL是單線程的,資源消耗更不可控(當(dāng)然ClickHouse本身也有相關(guān)參數(shù)可以配置查詢消耗的資源情況)。

2.”結(jié)果適合于單個(gè)服務(wù)器的RAM中”,結(jié)合上面所說(shuō),每條查詢都會(huì)消耗ClickHouse不少的(內(nèi)存)資源,因此不要無(wú)腦join大表,否則Memorylimitexceeded警告。

在開始更有意義的贊美之前,讓我再對(duì)ClickHouse進(jìn)行一些”自由的批評(píng)”:

1.盡管ClickHouse與mysql等數(shù)據(jù)庫(kù)一樣支持標(biāo)準(zhǔn)SQL語(yǔ)法(甚至兼容了mysql的G語(yǔ)法)以及窗口函數(shù)等,但是相關(guān)子查詢暫未支持,但將來(lái)會(huì)實(shí)現(xiàn)。

2.稀疏索引使得ClickHouse不適合通過(guò)其鍵檢索單行的點(diǎn)查詢。(稀疏索引只存儲(chǔ)非零值,因此在進(jìn)行點(diǎn)查詢時(shí)需要遍歷整個(gè)索引才能找到對(duì)應(yīng)的行,這會(huì)導(dǎo)致點(diǎn)查詢的性能較低)

ClickHouse基礎(chǔ)

連接及數(shù)據(jù)格式

連接方式

ClickHouse提供了HTTP和TCP以及gRPC三種方式的接口,非常方便,其中ClickHouse-client是基于TCP方式的,不同的client和服務(wù)器版本彼此兼容。

以HTTP接口方式訪問(wèn)時(shí),需注意使用GET方法請(qǐng)求時(shí)是默認(rèn)readonly的。換句話說(shuō),若要作修改數(shù)據(jù)的查詢,只能使用POST方法。

此外,除了上述的接口形式,ClickHouse甚至支持了MySQL wire通訊協(xié)議,生怕像我一樣的MySQL boy難以上手。簡(jiǎn)單的配置之后,就能輕松使用mysqlclient連接ClickHouse服務(wù)器,頗有import pytorch as tf之感(這何嘗不是一種語(yǔ)言層面的ntr)。不過(guò)也有一些限制,不支持prepared查詢以及某些數(shù)據(jù)類型會(huì)以字符串形式發(fā)送。同樣命運(yùn)的還有PostgreSQL

當(dāng)然,更常見(jiàn)的使用方式還是各語(yǔ)言實(shí)現(xiàn)的client庫(kù)。如今ClickHouse的生態(tài)早已成熟,無(wú)論是各類編程語(yǔ)言亦或是常見(jiàn)的InfrastructureProducts(怎么翻都別扭干脆貼原文,后同)(如kafka、k8s、grafana等),都有現(xiàn)成的庫(kù)將其結(jié)合起來(lái)使用。

數(shù)據(jù)格式

ClickHouse支持豐富的輸入/輸出格式,簡(jiǎn)單來(lái)說(shuō)就是TSV、CSVJSON、XMLProtobuf、二進(jìn)制格式以及一些Hadoop生態(tài)下常見(jiàn)的數(shù)據(jù)格式。此外ClickHouse本身也有一些模式推斷相關(guān)的函數(shù),能從文件/hdfs等數(shù)據(jù)源推斷出表的結(jié)構(gòu),算是個(gè)有趣的功能。

數(shù)據(jù)類型

常用的:

整型:追求極致性能的ClickHouse,自然是會(huì)在字節(jié)維度上錙銖必較的,整型類型的可選范圍為(U)Int8到Int256,當(dāng)然講究兼容的ClickHouse也是允許你定義BIGINT、BOOL、INT4之類的,會(huì)對(duì)應(yīng)到相應(yīng)的字節(jié)數(shù)類型上。什么,你還要像mysql那樣定義展示寬度(11)?對(duì)不起,做不到.jpg。

浮點(diǎn)數(shù)Float32?FLOAT、Float64?DOUBLE,需注意計(jì)算可能出現(xiàn)InfNaN

Bool:內(nèi)部等同于UInt8。

String:字節(jié)數(shù)沒(méi)有限制,與LONGTEXT,MEDIUMTEXT,TINYTEXT,TEXT,LONGBLOB,MEDIUMBLOB,TINYBLOB,BLOB,VARCHAR,CHAR同義。

Date:取值范圍[1970-01-01,2149-06-06](當(dāng)前)。

DateTime:具體到秒的時(shí)間??梢灾付〞r(shí)區(qū),如DateTime('Asia/Shanghai'),如不指定將使用ClickHouse服務(wù)器的時(shí)區(qū)設(shè)置。

時(shí)區(qū)僅用作以文本形式輸入輸出數(shù)據(jù)時(shí)的轉(zhuǎn)換(所以時(shí)區(qū)函數(shù)是沒(méi)有計(jì)算cost的),實(shí)際以unix timestamp存儲(chǔ)。因此,如果插入數(shù)據(jù)時(shí)寫211046400和1976-09-09 00:00:00是等效的(時(shí)區(qū)為東八區(qū)的話)。

array:定義方式為array(T),下標(biāo)起始為1,可以定義多維數(shù)組。數(shù)組元素最大可為一百萬(wàn)個(gè)。數(shù)組內(nèi)的元素類型需兼容,不兼容將拋出異常??赏ㄟ^(guò)sizeN-1快速獲得對(duì)應(yīng)第N維的長(zhǎng)度。

Tuple:定義方式為Tuple(arg1 type1,arg2 type2…)。后續(xù)可通過(guò)類似a.b的方式獲取對(duì)應(yīng)的值。元組間的比較為依次比較各元素大小。

Nullable:可用Nullable修飾一個(gè)類型,使其允許包含NULL值,代價(jià)是,被修飾的列無(wú)法作為表的索引項(xiàng)。同時(shí),為了存儲(chǔ)Nullable值,ClickHouse還會(huì)額外使用一個(gè)帶有NULL掩碼的文件來(lái)區(qū)分列的默認(rèn)值與NULL值,會(huì)在存儲(chǔ)空間以及性能上造成額外負(fù)擔(dān)。

也正是因?yàn)樘厥鈱?duì)待了Nullable的字段,可以用`字段名`.null(這個(gè)值將返回1或0標(biāo)識(shí)是否為空值)快速找到對(duì)應(yīng)字段為null的行。

總之,能用業(yè)務(wù)邏輯來(lái)區(qū)分空值,就盡量不要定義Nullable字段。

AggregateFunction:黑魔法,用法是AggregateFunction(func,types_of_argument..),如AggregateFunction(uniq,UInt64)。目前只支持uniq,anyIf和quantiles聚合函數(shù)。

可以配合xx-State函數(shù)得到中間狀態(tài),通過(guò)xx-Merge函數(shù)得到結(jié)果。好處就是可以將計(jì)算狀態(tài)序列化到表里,減少數(shù)據(jù)存儲(chǔ)量。通常是通過(guò)物化視圖實(shí)現(xiàn)的。

SimpleAggregateFunction:類似于AggregateFunction類型,支持更多的聚合函數(shù),且無(wú)需應(yīng)用xx-Merge和xx-State函數(shù)來(lái)得到值。

不常用的(我覺(jué)得):

Decimal

P-精度。有效范圍:[1:76],決定可以有多少個(gè)十進(jìn)制數(shù)字(包括分?jǐn)?shù))。

S-規(guī)模。有效范圍:[0:P],決定數(shù)字的小數(shù)部分中包含的小數(shù)位數(shù)。

FixedString(N):顧名思義,需注意N為字節(jié),當(dāng)字段的字節(jié)數(shù)剛好與指定的N相等時(shí)最高效,適合存一些明確的枚舉。超過(guò)會(huì)拋出異常。

UUID:配合generateUUIDv4函數(shù)食用更佳。

Date32:范圍為有符號(hào)32位整數(shù),表示相對(duì)1970-01-01的的天數(shù)。

DateTime64:時(shí)間范圍[1900-01-01 00:00:00,2299-12-31 23:59:59.99999999]。但不同于DateTime會(huì)與String自動(dòng)轉(zhuǎn)換,需借助諸如toDateTime64之類的時(shí)間處理函數(shù)。

枚舉:有Enum8和Enum16兩種類型,將預(yù)定字符串與整型數(shù)字關(guān)聯(lián)。插入枚舉值之外的值將拋出異常,枚舉值不能直接跟數(shù)字作比較。

LowCardinality:用法是LowCardinality(data_type),data_type的可選類型為String,F(xiàn)ixedString,Date,DateTime及除Decimal外的數(shù)字類型。

即將所在列的不同值映射到一個(gè)較短的編碼,當(dāng)少于10000個(gè)不同的值時(shí)ClickHouse可以進(jìn)行更高效的數(shù)據(jù)存儲(chǔ)和處理。比枚舉類型有更高的性能和靈活性。

域(Domain):域是出于使用戶易用等目的,在不修改原類型底層表示的情況下為基礎(chǔ)類型添加了部分特性的類型,用戶不能自定義域。目前有IPV4IPV6兩個(gè)類型,用途可顧名思義。

Nested:定義方式為Nested(name1Type1,Name2Type2,…),如DistrictNested(ProvinceString,CityString),后續(xù)就可以通過(guò)District.City訪問(wèn)具體值,將得到數(shù)組對(duì)象。(重生之我在DB定義結(jié)構(gòu)體)

flatten_nested設(shè)為0(非默認(rèn)值)可以無(wú)限套娃Nested類型。ALTER命令操作Nested類型會(huì)受限。

地理位置:包含了Point、Ring、Polygon、MultiPolygon四種類型,即Tuple(Float64,Float64),Array(Point),Array(Ring),Array(Polygon)。其中Polygon的表示方式為首元素為最外層輪廓的點(diǎn)集合,其余元素視作多邊形的”洞”。

字典:定義方式Map(key,value),key可為String,Integer,LowCardinality,FixedString,UUID,Date,DateTime,Date32,Enum,value類型任意,包括Map本身。取數(shù)時(shí)寫法也與各大編程語(yǔ)言相同,當(dāng)key不存在時(shí)默認(rèn)返回類型的零值,也支持a.keys和a.values這樣的語(yǔ)法。(Re:從零開始的異世界DB寫Map生活)

SQL語(yǔ)句

clickhouse使用入門(clickhouse使用教程)

ClickHouse支持的SQL語(yǔ)句如上所示,內(nèi)容太多了。。只簡(jiǎn)單挑些重點(diǎn)看下,先留個(gè)坑。

SELECT

小技巧:

select取最終列時(shí),可以使用COLUMNS表達(dá)式來(lái)以re2的正則表達(dá)式語(yǔ)法查找匹配的列,如COLUMNS(‘a(chǎn)’)可以匹配aa,ab列,效果類似python的re.search方法,查詢大寬表的時(shí),這個(gè)功能還是非常好用的。

此外,配合APPLY(<func>),EXCEPT(col_name..),REPLACE(<expr>ascol_name)這三個(gè)語(yǔ)法糖,有時(shí)能大大簡(jiǎn)化SQL,如:

SELECT COLUMNS(‘_w’) EXCEPT(‘test’) APPLY(max) from my_table

就能迅速找出帶_w且不帶test的列,并計(jì)算他們的最大值。(想想有時(shí)只需要簡(jiǎn)單分析部分列,卻要施法吟唱半天)

有時(shí)需要對(duì)單獨(dú)某個(gè)查詢?cè)O(shè)置特殊配置時(shí),也可在語(yǔ)句最后直接加上SETTINGS xx,這樣配置就只會(huì)對(duì)本次查詢生效。

ARRAY JOIN:

用于生成一個(gè)新表,該表具有包含該初始列中的每個(gè)單獨(dú)數(shù)組元素的列,而其他列的值將被重復(fù)顯示。單行變多行的經(jīng)典操作??諗?shù)組將不包含在結(jié)果中,LEFT ARRAY JOIN則會(huì)包含。

可同時(shí)ARRAY JOIN多個(gè)數(shù)組,這種情況下得到的結(jié)果并非笛卡爾積。也可以ARRAY JOIN Nested類型。

DISTINCT

如果需要只對(duì)某幾列去重,需用DISTINCTON(column1,column2..),否則視作對(duì)全部列去重。DISTINCT子句是先于ORDER BY子句執(zhí)行的。

與不使用聚合函數(shù)而對(duì)某些列進(jìn)行GROUPBY相比,結(jié)果一般是相同的,但使用DISTINCT時(shí),已處理的數(shù)據(jù)塊會(huì)立馬輸出,而無(wú)需等待整個(gè)查詢執(zhí)行完成。

INTERSECT、UNION、EXCEPT

將兩個(gè)查詢進(jìn)行交并補(bǔ),列數(shù)等信息需匹配。重復(fù)行多時(shí)INTERSECT DISTINCT效果更好。

FROM

可在數(shù)據(jù)源名后加上FINAL修飾符,ClickHouse會(huì)在返回結(jié)果之前完全合并數(shù)據(jù),從而執(zhí)行給定表引擎合并期間發(fā)生的所有數(shù)據(jù)轉(zhuǎn)換。只適用于MergeTree-引擎族。使用FINAL修飾符的SELECT查詢啟用了并發(fā)執(zhí)行,但仍比不帶FINAL的查詢更慢,一是因?yàn)檫@會(huì)在查詢執(zhí)行過(guò)程中合并數(shù)據(jù),二是FINAL會(huì)額外讀取主鍵列。多數(shù)情況下不推薦使用,通常可以通過(guò)假設(shè)MergeTree的后臺(tái)進(jìn)程還未生效(引擎部分再談),并使用聚合函數(shù)來(lái)達(dá)到同樣效果。

此外不同于很多數(shù)據(jù)庫(kù)在你缺失相關(guān)參數(shù)時(shí)給個(gè)錯(cuò)誤,ClickHouse在很多地方都做了默認(rèn)參數(shù)的設(shè)置。比如在你不指定FROM子句時(shí),默認(rèn)從system.one表查詢,以及支持select count()(會(huì)傾向于選取最小的列進(jìn)行計(jì)數(shù))這樣的寫法。不過(guò)這好不好嘛,還是智者見(jiàn)智仁者見(jiàn)仁,在不理解的情況下被暗戳戳地坑一把也是可能的。

Join:

除了支持標(biāo)準(zhǔn)的SQL JOIN類型,還支持ASOF JOIN,常用于根據(jù)時(shí)間序列不完全匹配地join多個(gè)表,比如用來(lái)匹配用戶事件活動(dòng)記錄。

涉及到分布式表的join:

當(dāng)使用普通JOIN時(shí),將查詢發(fā)送到遠(yuǎn)程服務(wù)器。在每個(gè)服務(wù)器上單獨(dú)形成右表。

當(dāng)使用GLOBAL … JOIN時(shí),首先請(qǐng)求者服務(wù)器運(yùn)行一個(gè)子查詢來(lái)計(jì)算正確的表。此臨時(shí)表將傳遞到每個(gè)遠(yuǎn)程服務(wù)器,并使用傳輸?shù)呐R時(shí)數(shù)據(jù)對(duì)其運(yùn)行查詢。

當(dāng)運(yùn)行JOIN操作時(shí),與查詢的其他階段相比,執(zhí)行順序沒(méi)有進(jìn)行優(yōu)化。JOIN操作會(huì)在WHERE過(guò)濾和聚合之前運(yùn)行。

同樣的join操作在子查詢中又會(huì)再次執(zhí)行一次,要避免這種情況可以考慮使用Join這個(gè)表引擎。

默認(rèn)情況下,ClickHouse使用哈希聯(lián)接算法。 ClickHouse取右表并在內(nèi)存中為其創(chuàng)建哈希表。(所以一個(gè)很重要的最佳實(shí)踐是join表時(shí)把小表放在右表)在達(dá)到某個(gè)內(nèi)存消耗閾值后,ClickHouse會(huì)回退到合并聯(lián)接算法。

INSERT INTO

插入數(shù)據(jù)時(shí)會(huì)對(duì)寫入的數(shù)據(jù)進(jìn)行一些處理,按照主鍵排序,按照分區(qū)鍵對(duì)數(shù)據(jù)進(jìn)行分區(qū)等。所以如果在寫入數(shù)據(jù)中包含多個(gè)分區(qū)的混合數(shù)據(jù)時(shí),將會(huì)顯著的降低INSERT的性能。為了避免這種情況:

  • 數(shù)據(jù)總是以盡量大的batch進(jìn)行寫入,如每次寫入100,000行。
  • 數(shù)據(jù)在寫入ClickHouse前預(yù)先的對(duì)數(shù)據(jù)進(jìn)行分組。

在以下的情況下,性能不會(huì)下降:

  • 數(shù)據(jù)總是被實(shí)時(shí)的寫入。
  • 寫入的數(shù)據(jù)已經(jīng)按照時(shí)間排序。

也可以異步的、小規(guī)模的插入數(shù)據(jù),這些數(shù)據(jù)會(huì)被合并成多個(gè)批次,然后安全地寫入到表中。這是通過(guò)設(shè)置async_insert來(lái)實(shí)現(xiàn)的,異步插入的方式只支持HTTP協(xié)議,并且不支持?jǐn)?shù)據(jù)去重。

CREATE

Materialized(物化視圖)

創(chuàng)建語(yǔ)法:

CREATE MATERIALIZED VIEW [IF NOT exists] [db.]table_name [ON CLUSTER] [TO[db.]name] [ENGINE = engine] [POPULATE] AS SELECT …

創(chuàng)建不帶TO [db].[table]的物化視圖時(shí),必須指定ENGINE–用于存儲(chǔ)數(shù)據(jù)的表引擎。

使用TO [db].[table]創(chuàng)建物化視圖時(shí),不得使用POPULATE。

具體實(shí)現(xiàn):當(dāng)向SELECT中指定的表插入數(shù)據(jù)時(shí),插入數(shù)據(jù)的一部分被這個(gè)SELECT查詢轉(zhuǎn)換,結(jié)果插入到視圖中。

ClickHouse 中的物化視圖更像是插入觸發(fā)器。 如果視圖查詢中有一些聚合,則它僅應(yīng)用于一批新插入的數(shù)據(jù)。對(duì)源表現(xiàn)有數(shù)據(jù)的任何更改(如更新、刪除、刪除分區(qū)等)都不會(huì)更改物化視圖。

ClickHouse 中的物化視圖在出現(xiàn)錯(cuò)誤時(shí)沒(méi)有確定性行為。這意味著已經(jīng)寫入的塊將保留在目標(biāo)表中,但出現(xiàn)錯(cuò)誤后的所有塊則不會(huì)寫入。

如果指定POPULATE,則在創(chuàng)建視圖時(shí)將現(xiàn)有表數(shù)據(jù)插入到視圖中,就像創(chuàng)建一個(gè)CREATE TABLE … AS SELECT …一樣。否則,查詢僅包含創(chuàng)建視圖后插入表中的數(shù)據(jù)。不建議使用POPULATE,因?yàn)樵趧?chuàng)建視圖期間插入表中的數(shù)據(jù)不會(huì)插入其中。

SELECT查詢可以包含DISTINCT、GROUP BY、ORDER BY、LIMIT……請(qǐng)注意,相應(yīng)的轉(zhuǎn)換是在每個(gè)插入數(shù)據(jù)塊上獨(dú)立執(zhí)行的。 例如,如果設(shè)置了GROUP BY,則在插入期間聚合數(shù)據(jù),但僅在插入數(shù)據(jù)的單個(gè)數(shù)據(jù)包內(nèi)。數(shù)據(jù)不會(huì)被進(jìn)一步聚合。例外情況是使用獨(dú)立執(zhí)行數(shù)據(jù)聚合的ENGINE,例如SummingMergeTree。

在物化視圖上執(zhí)行ALTER查詢有局限性,因此可能不方便。如果物化視圖使用構(gòu)造TO [db.]name,你可以DETACH視圖,為目標(biāo)表運(yùn)行ALTER,然后ATTACH先前分離的視圖。

視圖看起來(lái)與普通表相同。 例如,它們列在SHOW TABLES查詢的結(jié)果中。

ALTER

UPDATE

沒(méi)錯(cuò),update操作被置于ALTER操作下,這意味著ClickHouse的update操作不像oltp數(shù)據(jù)庫(kù)那般輕量級(jí),應(yīng)盡量避免使用。是通過(guò)mutation來(lái)實(shí)現(xiàn)的。

Mutations(突變)

用來(lái)操作表數(shù)據(jù)的ALTER查詢是通過(guò)一種叫做“突變”的機(jī)制來(lái)實(shí)現(xiàn)的,最明顯的是ALTER TABLE … DELETE和ALTER TABLE … UPDATE。它們是異步的后臺(tái)進(jìn)程,類似于MergeTree表的合并,產(chǎn)生新的“突變”版本的數(shù)據(jù)part(后面會(huì)詮釋這個(gè)概念)。

對(duì)于*MergeTree表,通過(guò)重寫整個(gè)數(shù)據(jù)part來(lái)執(zhí)行突變。沒(méi)有原子性——一旦突變的part準(zhǔn)備好,part就會(huì)被替換,并且在突變期間開始執(zhí)行的SELECT查詢將看到來(lái)自已經(jīng)突變的part的數(shù)據(jù),以及來(lái)自尚未突變的part的數(shù)據(jù)。

突變完全按照它們的產(chǎn)生順序排列,并按此順序應(yīng)用于每個(gè)part。突變還與“INSERT INTO”查詢進(jìn)行排序:在提交突變之前插入表中的數(shù)據(jù)將被突變,而在此之后插入的數(shù)據(jù)將不會(huì)被突變。注意,突變不會(huì)以任何方式阻止插入。

突變查詢?cè)谔砑油蛔儣l目后立即返回(對(duì)于復(fù)制表是到ZooKeeper,對(duì)于非復(fù)制表到文件系統(tǒng))。突變本身使用系統(tǒng)配置文件來(lái)配置異步執(zhí)行。要跟蹤突變的進(jìn)程,可以使用system.mutations表。成功提交的變異將繼續(xù)執(zhí)行,即使ClickHouse服務(wù)器重新啟動(dòng)。沒(méi)有辦法回滾突變一旦提交,但如果突變卡住了,可以使用KILL MUTATION阻止突變的執(zhí)行。

完成突變的條目不會(huì)立即刪除(保留條目的數(shù)量由finished_mutations_to_keep存儲(chǔ)引擎參數(shù)決定)。

DELETE

刪除的行會(huì)被立即標(biāo)記為已刪除,并將自動(dòng)從所有后續(xù)查詢中過(guò)濾掉。數(shù)據(jù)清理在后臺(tái)異步發(fā)生。此功能僅適用于 MergeTree 表引擎系列。這就是ClickHouse的輕量級(jí)刪除

原理:當(dāng)執(zhí)行DELETE時(shí),ClickHouse 僅保存一個(gè)掩碼,其中每一行都被標(biāo)記為“現(xiàn)有”或“已刪除”。 掩碼實(shí)現(xiàn)為一個(gè)隱藏的_row_exists系統(tǒng)列,所有可見(jiàn)行該列存儲(chǔ)為 True,刪除的行存儲(chǔ)為False。僅當(dāng)一個(gè)數(shù)據(jù)part中部分行被刪除了,這個(gè)字段才會(huì)出現(xiàn)。

DELETE操作實(shí)際上是被翻譯成ALTER TABLE update _row_exists = 0 WHERE …的mutation操作。

引擎

數(shù)據(jù)庫(kù)引擎

Atomic

ClickHouse的默認(rèn)數(shù)據(jù)庫(kù)引擎,支持非阻塞的DROP TABLE、RENAME TABLE和具有原子性的EXCHANGE TABLE操作。

DROP TABLE時(shí)只會(huì)將表標(biāo)記為已刪除,并且把元數(shù)據(jù)移到/clickhouse_path/metadata_dropped/,然后通知后臺(tái)線程稍后刪除,這個(gè)延遲時(shí)間可指定,也可設(shè)為同步刪除。

Lazy

在最后一次訪問(wèn)之后,只在內(nèi)存中保存expiration_time_in_seconds秒。只能用于*Log表。它是為存儲(chǔ)許多小的*Log表而優(yōu)化的,對(duì)于這些表,訪問(wèn)之間有很長(zhǎng)的時(shí)間間隔。

PostgreSQL、MySQL、SQLite

……用于在ClickHouse與上述三種數(shù)據(jù)庫(kù)間交(tou)換(jia)數(shù)據(jù)。其中不能在MySQL引擎上執(zhí)行RENAME、CREATETABLE和ALTER來(lái)修改表的結(jié)構(gòu)。

另外還有幾個(gè)實(shí)驗(yàn)性的引擎,不談。

表引擎

表引擎(即表的類型)決定了:

  • 數(shù)據(jù)的存儲(chǔ)方式和位置,寫到哪里以及從哪里讀取數(shù)據(jù)
  • 支持哪些查詢以及如何支持。
  • 并發(fā)數(shù)據(jù)訪問(wèn)。
  • 索引的使用(如果存在)。
  • 是否可以執(zhí)行多線程請(qǐng)求。
  • 數(shù)據(jù)復(fù)制參數(shù)。

MergeTree系列

MergeTree系列的引擎是ClickHouse中最核心的引擎,提供了列式存儲(chǔ)、自定義分區(qū)、稀疏主鍵索引和二級(jí)跳數(shù)索引等功能?;贛ergeTree的引擎都在部分特定用例下添加了額外的功能,而且通常是在后臺(tái)執(zhí)行額外的數(shù)據(jù)操作來(lái)實(shí)現(xiàn)的。缺點(diǎn)是這些引擎相對(duì)笨重,如果需要許多小表來(lái)存一些臨時(shí)數(shù)據(jù),可以考慮Log系列引擎。

MergeTree

主要特點(diǎn)

  1. 存儲(chǔ)按主鍵排序。
  2. 指定了分區(qū)鍵時(shí),會(huì)截取分區(qū)數(shù)據(jù),增加查詢效率。
  3. 支持?jǐn)?shù)據(jù)采樣。

完整語(yǔ)句參考

clickhouse使用入門(clickhouse使用教程)

重要參數(shù)說(shuō)明

ORDER BY:排序鍵

如果沒(méi)有用PRIMARY KEY明確定義主鍵,那么該鍵將被當(dāng)做主鍵。

如果不需要排序,可以使用ORDERBY tuple()。

排序鍵包含多列時(shí),查詢時(shí)走索引依然遵循最左匹配規(guī)則。

PARTITION BY:分區(qū)鍵

大多數(shù)情況下,不需要分使用區(qū)鍵。即使需要使用,也不需要使用比月更細(xì)粒度的分區(qū)鍵。分區(qū)不會(huì)加快查詢(這與ORDER BY表達(dá)式不同)。永遠(yuǎn)也別使用過(guò)細(xì)粒度的分區(qū)鍵。

要按月分區(qū),可以使用表達(dá)式toYYYYMM(date_column)。

PRIMARY KEY:主鍵

大部分情況下不需要再專門指定一個(gè)PRIMARY KEY子句。ClickHouse不要求主鍵唯一。

INDEX:跳數(shù)索引

后面介紹。

存儲(chǔ)細(xì)節(jié)

不同分區(qū)的數(shù)據(jù)會(huì)被分成不同的片段(part,后同),ClickHouse在后臺(tái)合并數(shù)據(jù)片段以便更高效存儲(chǔ)。

數(shù)據(jù)片段可以以Wide或Compact格式存儲(chǔ)。在Wide格式下,每一列都會(huì)在文件系統(tǒng)中存儲(chǔ)為單獨(dú)的文件,在Compact格式下所有列都存儲(chǔ)在一個(gè)文件中。Compact格式可以提高插入量少插入頻率頻繁時(shí)的性能。

每個(gè)數(shù)據(jù)片段被邏輯的分割成顆粒(granules)。顆粒是ClickHouse中進(jìn)行數(shù)據(jù)查詢時(shí)的最小不可分割數(shù)據(jù)集。ClickHouse不會(huì)對(duì)行或值進(jìn)行拆分,所以每個(gè)顆??偸前麛?shù)個(gè)行。每個(gè)顆粒的第一行通過(guò)該行的主鍵值進(jìn)行標(biāo)記,ClickHouse會(huì)為每個(gè)數(shù)據(jù)片段創(chuàng)建一個(gè)索引文件來(lái)存儲(chǔ)這些標(biāo)記。對(duì)于每列,無(wú)論它是否包含在主鍵當(dāng)中,ClickHouse都會(huì)存儲(chǔ)類似標(biāo)記。

顆粒的大小通過(guò)表引擎參數(shù)index_granularity(默認(rèn)8192)和index_granularity_bytes(10Mb)控制。顆粒的行數(shù)的在[1,index_granularity]范圍中,這取決于行的大小。如果單行的大小超過(guò)了index_granularity_bytes設(shè)置的值,那么一個(gè)顆粒的大小會(huì)超過(guò)index_granularity_bytes。在這種情況下,顆粒的大小等于該行的大小。

詳談主鍵與索引

主鍵的選擇

稀疏索引使得ClickHouse可以處理極大量的行,因?yàn)榇蠖鄶?shù)情況下,這些索引常駐于內(nèi)存。

長(zhǎng)的主鍵會(huì)對(duì)插入性能和內(nèi)存消耗有負(fù)面影響,但主鍵中額外的列并不影響SELECT查詢的性能。

可以使用ORDER BY tuple()語(yǔ)法創(chuàng)建沒(méi)有主鍵的表。在這種情況下ClickHouse根據(jù)數(shù)據(jù)插入的順序存儲(chǔ)。如果在使用INSERT…SELECT時(shí)希望保持?jǐn)?shù)據(jù)的排序,可以設(shè)置max_insert_threads=1。

主鍵與排序鍵不同的情況

ClickHouse可以做到指定一個(gè)跟排序鍵不一樣的主鍵,此時(shí)排序鍵用于在數(shù)據(jù)片段中進(jìn)行排序,主鍵用于在索引文件中進(jìn)行標(biāo)記的寫入。這種情況下,主鍵表達(dá)式元組必須是排序鍵表達(dá)式元組的前綴。

當(dāng)使用SummingMergeTree和AggregatingMergeTree引擎時(shí),這個(gè)特性非常有用。通常在使用這類引擎時(shí),表里的列分兩種:維度和度量。典型的查詢會(huì)通過(guò)任意的GROUP BY對(duì)度量列進(jìn)行聚合并通過(guò)維度列進(jìn)行過(guò)濾。由于SummingMergeTree和AggregatingMergeTree會(huì)對(duì)排序鍵相同的行進(jìn)行聚合,所以把所有的維度放進(jìn)排序鍵是很自然的做法。但這將導(dǎo)致排序鍵中包含大量的列,并且排序鍵會(huì)伴隨著新添加的維度不斷的更新。

在這種情況下合理的做法是,只保留少量的列在主鍵當(dāng)中用于提升掃描效率,將維度列添加到排序鍵中。

部分單調(diào)序列

如一個(gè)月中的天數(shù)。它們?cè)谝粋€(gè)月的范圍內(nèi)形成一個(gè)單調(diào)序列,但如果擴(kuò)展到更大的時(shí)間范圍它們就不再單調(diào)了,這就是一個(gè)部分單調(diào)序列。如果用戶使用部分單調(diào)的主鍵創(chuàng)建表,ClickHouse同樣會(huì)創(chuàng)建一個(gè)稀疏索引。當(dāng)用戶從這類表中查詢數(shù)據(jù)時(shí),ClickHouse會(huì)對(duì)查詢條件進(jìn)行分析。如果用戶希望獲取兩個(gè)索引標(biāo)記之間的數(shù)據(jù)并且這兩個(gè)標(biāo)記在一個(gè)月以內(nèi),ClickHouse可以在這種特殊情況下使用到索引,因?yàn)樗梢杂?jì)算出查詢參數(shù)與索引標(biāo)記之間的距離。

如果查詢參數(shù)范圍內(nèi)的主鍵不是單調(diào)序列,那么ClickHouse無(wú)法使用索引。

ClickHouse在任何主鍵代表一個(gè)部分單調(diào)序列的情況下都會(huì)使用這個(gè)邏輯。(這個(gè)故事告訴我們?yōu)槭裁茨J(rèn)主鍵和排序鍵相同)

跳數(shù)索引

示例:INDEX a(u64*i32,s) TYPE minmax GRANULARITY 3。復(fù)合列上也能創(chuàng)建。

*MergeTree系列的表可以指定跳數(shù)索引。跳數(shù)索引是指數(shù)據(jù)片段按照粒度分割成小塊后,將上述SQL的granularity_value數(shù)量的小塊組合成一個(gè)大的塊,對(duì)這些大塊寫入索引信息,這樣有助于使用where篩選時(shí)跳過(guò)大量不必要的數(shù)據(jù),減少SELECT需要讀取的數(shù)據(jù)量。

Projection

投影(projection)類似于物化視圖,但存儲(chǔ)在分區(qū)目錄,即與原表的數(shù)據(jù)分區(qū)在同一個(gè)分區(qū)目錄下??赏ㄟ^(guò)投影定義語(yǔ)句SELECT <column list expr> [GROUP BY] <group keys expr> [ORDER BY] <expr>生成。使用可能還需要配置一些參數(shù)。

如指定了Group by子句則投影的引擎將變?yōu)锳ggregatingMergeTree,同時(shí)所有的聚合函數(shù)變?yōu)锳ggregateFunction。指定了ORDER BY子句則會(huì)使用對(duì)應(yīng)的key作為主鍵。更多示例可參考:2021年ClickHouse最王炸功能來(lái)襲,性能輕松提升40倍。

簡(jiǎn)單來(lái)說(shuō),跟物化視圖的區(qū)別可以看作是——不用再顯式定義一個(gè)物化視圖了,對(duì)應(yīng)用層屏蔽了基礎(chǔ)數(shù)據(jù)和統(tǒng)計(jì)數(shù)據(jù)的區(qū)別。兩類數(shù)據(jù)你都直接查原表即可。

并發(fā)訪問(wèn)

MergeTree引擎也是MVCC(多版本并發(fā)控制)的。

列與表的TTL

設(shè)置TTL即設(shè)置數(shù)據(jù)的過(guò)期時(shí)間,當(dāng)列的TTL過(guò)期時(shí),ClickHouse會(huì)將數(shù)據(jù)替換成對(duì)應(yīng)數(shù)據(jù)類型的默認(rèn)值,當(dāng)該列所有數(shù)據(jù)都過(guò)期時(shí),該列的數(shù)據(jù)將會(huì)被刪除。(列式數(shù)據(jù)庫(kù),小子?。?/span>主鍵列不可指定。

當(dāng)表的TTL過(guò)期時(shí),過(guò)期行會(huì)被操作(刪除或轉(zhuǎn)移),還可通過(guò)WHERE和GROUP BY條件指定符合條件的行。GROUP BY表達(dá)式必須是表主鍵的前綴。

數(shù)據(jù)副本

MergeTree系列的引擎的表都支持?jǐn)?shù)據(jù)副本,只需在引擎名前加上Replicated。

ReplacingMergeTree

該引擎和MergeTree的不同之處在于它會(huì)刪除排序鍵值相同的重復(fù)項(xiàng),適用于在后臺(tái)清除重復(fù)的數(shù)據(jù)以節(jié)省空間。但只會(huì)在數(shù)據(jù)合并期間進(jìn)行,而合并會(huì)在后臺(tái)一個(gè)不確定的時(shí)間進(jìn)行。雖然可以調(diào)用OPTIMIZE語(yǔ)句發(fā)起計(jì)劃外的合并,但須知OPTIMIZE語(yǔ)句會(huì)引發(fā)對(duì)數(shù)據(jù)的大量讀寫。

SummingMergeTree

當(dāng)合并SummingMergeTree表的數(shù)據(jù)片段時(shí),ClickHouse會(huì)把所有具有相同主鍵的行合并為一行,該行包含了被合并的行中具有數(shù)值數(shù)據(jù)類型的列的sum值。即便如此,當(dāng)需要聚合數(shù)據(jù)時(shí)仍應(yīng)該使用sum函數(shù)來(lái)聚合,因?yàn)楹笈_(tái)合并的時(shí)間是不確定的。

對(duì)于AggregateFunction 類型的列,ClickHouse 根據(jù)對(duì)應(yīng)函數(shù)表現(xiàn)為AggregatingMergeTree引擎的聚合。

而對(duì)于Nested類型的列,ClickHouse會(huì)將第一列視作key,其他列視作values進(jìn)行聚合。

AggregatingMergeTree

將一個(gè)數(shù)據(jù)片段內(nèi)所有具有相同排序鍵的行替換成一行,這一行會(huì)存儲(chǔ)一系列聚合函數(shù)的狀態(tài)。引擎使用AggregateFunction和SimpleAggregateFunction類型來(lái)處理所有列??梢钥醋鯯ummingMergeTree是AggregatingMergeTree的特化(表現(xiàn)上而言)。

可以使用AggregatingMergeTree表來(lái)做增量數(shù)據(jù)的聚合統(tǒng)計(jì),包括物化視圖的數(shù)據(jù)聚合。

要插入數(shù)據(jù),需使用帶有-State-聚合函數(shù)的INSERT SELECT語(yǔ)句。從AggregatingMergeTree表中查詢數(shù)據(jù)時(shí),需使用GROUP BY子句并且要使用與插入時(shí)相同的聚合函數(shù),但后綴要改為-Merge。

CollapsingMergeTree

CollapsingMergeTree 會(huì)異步的刪除(折疊)這些除了特定列 Sign 有 1 和 -1 的值以外,其余所有字段的值都相等的成對(duì)的行。沒(méi)有成對(duì)的行將會(huì)被保留。

Sign為1和-1的行應(yīng)按照一定的順序?qū)懭?,合并相?dāng)取決于記錄的一致性,否則實(shí)現(xiàn)不了預(yù)期的折疊效果(即先Sign=1后Sign=-1),聚合統(tǒng)計(jì)時(shí)也應(yīng)考慮上Sign字段對(duì)結(jié)果的影響??梢允褂肍inal修飾符強(qiáng)制進(jìn)行折疊而不聚合,但是效率低下。

此外,插入時(shí)Sign=1和Sign=-1的記錄應(yīng)該在兩次insert語(yǔ)句中分別插入,以保證他們?cè)诓煌臄?shù)據(jù)片段(part),否則也不會(huì)執(zhí)行合并操作。

個(gè)人覺(jué)得,難用(其實(shí)我想說(shuō)沒(méi)用),或者是我沒(méi)找到正確的打開方式。

VersionedCollapsingMergeTree

顧名思義,是上面那位的兄弟,只不過(guò)多了一個(gè)Version列,允許以多個(gè)線程的任何順序插入數(shù)據(jù)。Version列有助于正確折疊行,即使它們以錯(cuò)誤的順序插入。

當(dāng)ClickHouse合并數(shù)據(jù)部分時(shí),它會(huì)刪除具有相同主鍵和版本但Sign值不同的一對(duì)行。

當(dāng)ClickHouse插入數(shù)據(jù)時(shí),它會(huì)按主鍵對(duì)行進(jìn)行排序。 如果Version列不在主鍵中,ClickHouse將其隱式添加到主鍵作為最后一個(gè)字段并使用它進(jìn)行排序。

由于ClickHouse具有不保證具有相同主鍵的所有行都將位于相同的結(jié)果數(shù)據(jù)片段中,甚至位于相同的物理服務(wù)器上的特性,以及上面說(shuō)的數(shù)據(jù)合并時(shí)機(jī)的不確定性,所以想要最終的數(shù)據(jù)還是免不了group by等聚合操作。

GraphiteMergeTree

該引擎用來(lái)對(duì)Graphite類型數(shù)據(jù)進(jìn)行瘦身及匯總。如果不需要對(duì)Graphite數(shù)據(jù)做匯總,那么可以使用任意的表引擎;但若需要,那就采用GraphiteMergeTree引擎。它能減少存儲(chǔ)空間,同時(shí)能提高Graphite數(shù)據(jù)的查詢效率。

Log引擎系列

共同特點(diǎn):

  • 數(shù)據(jù)存儲(chǔ)在磁盤上。
  • 寫入時(shí)將數(shù)據(jù)追加在文件末尾。
  • 支持并發(fā)訪問(wèn)數(shù)據(jù)時(shí)上鎖。(執(zhí)行insert語(yǔ)句時(shí),表會(huì)被上寫鎖)
  • 不支持突變操作。(參見(jiàn)alter)
  • 不支持索引。(表明范圍查詢效率不高)
  • 非原子地寫入數(shù)據(jù)。

各引擎差異:

Log引擎為表中的每一列使用不同的文件。StripeLog將所有的數(shù)據(jù)存儲(chǔ)在一個(gè)文件中。因此StripeLog引擎在操作系統(tǒng)中使用更少的描述符,但是Log引擎提供更高的讀性能。兩者都支持并發(fā)的數(shù)據(jù)讀取。

TinyLog引擎是該系列中最簡(jiǎn)單的引擎并且提供了最少的功能和最低的性能。TinyLog引擎不支持并行讀取和并發(fā)數(shù)據(jù)訪問(wèn),并將每一列存儲(chǔ)在不同的文件中。

Log

Log與TinyLog的不同之處在于,”標(biāo)記” 的小文件與列文件存在一起。這些標(biāo)記寫在每個(gè)數(shù)據(jù)塊上,并且包含偏移量,這些偏移量指示從哪里開始讀取文件以便跳過(guò)指定的行數(shù)。這使得可以在多個(gè)線程中讀取表數(shù)據(jù)。Log引擎適用于臨時(shí)數(shù)據(jù)。

StripeLog

需要寫入許多小數(shù)據(jù)量(小于一百萬(wàn)行)的表的場(chǎng)景下使用這個(gè)引擎。

寫數(shù)據(jù)

StripeLog引擎將所有列存儲(chǔ)在一個(gè)文件中。對(duì)每一次Insert請(qǐng)求,ClickHouse 將數(shù)據(jù)塊追加在表文件的末尾,逐列寫入。

ClickHouse 為每張表寫入以下文件:

  • data.bin— 數(shù)據(jù)文件。
  • index.mrk— 帶標(biāo)記的文件。標(biāo)記包含了已插入的每個(gè)數(shù)據(jù)塊中每列的偏移量。

StripeLog引擎不支持ALTER UPDATE和ALTER DELETE操作。

讀數(shù)據(jù)

帶標(biāo)記的文件使得 ClickHouse 可以并行的讀取數(shù)據(jù)。這意味著SELECT請(qǐng)求返回行的順序是不可預(yù)測(cè)的。

TinyLog

此表引擎通常使用場(chǎng)景:一次寫入數(shù)據(jù),然后根據(jù)需要多次讀取。

查詢?cè)趩蝹€(gè)流中執(zhí)行。該引擎適用于相對(duì)較小的表(最多約 1,000,000 行)。如果你有很多小表,使用這個(gè)表引擎是有意義的,因?yàn)樗热罩疽娓?jiǎn)單(需要打開的文件更少)。

與外部系統(tǒng)集成的引擎

正如上面提到的ClickHouse對(duì)mysql等數(shù)據(jù)庫(kù)的"支持",實(shí)際上在表引擎上也提供了與外部系統(tǒng)的多種集成方式,如下所示。具體不再介紹,有需要可以去官網(wǎng)了解。

clickhouse使用入門(clickhouse使用教程)

其他特殊引擎:

Distributed

分布式引擎本身不存儲(chǔ)數(shù)據(jù), 但可以在多個(gè)服務(wù)器上進(jìn)行分布式查詢。 讀是自動(dòng)并行的。讀取時(shí),遠(yuǎn)程服務(wù)器表的索引(如果有的話)會(huì)被使用。

創(chuàng)建語(yǔ)法:

clickhouse使用入門(clickhouse使用教程)

也可使用AS語(yǔ)法使得分布式表指向本地表。

分布式引擎參數(shù)

  • cluster– 服務(wù)為配置中的集群名
  • database– 遠(yuǎn)程數(shù)據(jù)庫(kù)名
  • table– 遠(yuǎn)程數(shù)據(jù)表名
  • sharding_key– (可選) 分片key
  • policy_name– (可選) 規(guī)則名,它會(huì)被用作存儲(chǔ)臨時(shí)文件以便異步發(fā)送數(shù)據(jù)

settings中可進(jìn)行一些分布式設(shè)置。

數(shù)據(jù)不僅在遠(yuǎn)程服務(wù)器上讀取,而且在遠(yuǎn)程服務(wù)器上進(jìn)行部分處理。例如,對(duì)于帶有 GROUP BY的查詢,數(shù)據(jù)將在遠(yuǎn)程服務(wù)器上聚合,聚合函數(shù)的中間狀態(tài)將被發(fā)送到請(qǐng)求者服務(wù)器。然后將進(jìn)一步聚合數(shù)據(jù)。

集群:

集群是通過(guò)服務(wù)器配置文件來(lái)配置的。集群名稱不能包含點(diǎn)號(hào)。

配置了副本后,讀取操作會(huì)從每個(gè)分片里選擇一個(gè)可用的副本??膳渲秘?fù)載平衡算法。 如果跟服務(wù)器的連接不可用,則會(huì)嘗試短超時(shí)的重連。如果重連失敗,則選擇下一個(gè)副本,依此類推。如果跟所有副本的連接嘗試都失敗,則嘗試用相同的方式再重復(fù)幾次。

要查看集群信息,可通過(guò)system.clusters表。

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

向集群寫數(shù)據(jù)的方法有兩種:

一,自已指定要將哪些數(shù)據(jù)寫入哪些服務(wù)器,并直接在每個(gè)分片上執(zhí)行寫入。這是最靈活的解決方案 – 你可以使用任何分片方案,對(duì)于復(fù)雜業(yè)務(wù)特性的需求,這可能是非常重要的。這也是最佳解決方案,因?yàn)閿?shù)據(jù)可以完全獨(dú)立地寫入不同的分片。

二,在分布式表上執(zhí)行 INSERT。(噠咩,不推薦)在這種情況下,分布式表會(huì)跨服務(wù)器分發(fā)插入數(shù)據(jù)。為了寫入分布式表,必須要配置分片鍵(最后一個(gè)參數(shù))。當(dāng)然,如果只有一個(gè)分片,則寫操作在沒(méi)有分片鍵的情況下也能工作,因?yàn)檫@種情況下分片鍵沒(méi)有意義。

數(shù)據(jù)是異步寫入的。對(duì)于分布式表的 INSERT,數(shù)據(jù)塊只寫本地文件系統(tǒng)。之后會(huì)盡快地在后臺(tái)發(fā)送到遠(yuǎn)程服務(wù)器。

如果在 INSERT 到分布式表時(shí)服務(wù)器節(jié)點(diǎn)丟失或重啟(如,設(shè)備故障),則插入的數(shù)據(jù)可能會(huì)丟失。如果在表目錄中檢測(cè)到損壞的數(shù)據(jù)分片,則會(huì)將其轉(zhuǎn)移到broken子目錄,并不再使用。

關(guān)于分片:

分片可在配置文件中定義‘internal_replication’參數(shù)。

此參數(shù)設(shè)置為true時(shí),寫操作只選一個(gè)正常的副本寫入數(shù)據(jù)。如果分布式表的子表是復(fù)制表(*ReplicaMergeTree),請(qǐng)使用此方案。換句話說(shuō),這其實(shí)是把數(shù)據(jù)的復(fù)制工作交給實(shí)際需要寫入數(shù)據(jù)的表本身而不是分布式表。

若此參數(shù)設(shè)置為false(默認(rèn)值),寫操作會(huì)將數(shù)據(jù)寫入所有副本。實(shí)質(zhì)上,這意味著要分布式表本身來(lái)復(fù)制數(shù)據(jù)。這種方式不如使用復(fù)制表的好,因?yàn)椴粫?huì)檢查副本的一致性,并且隨著時(shí)間的推移,副本數(shù)據(jù)可能會(huì)有些不一樣。

選擇將一行數(shù)據(jù)發(fā)送到哪個(gè)分片的方法是,首先計(jì)算分片表達(dá)式,然后將這個(gè)計(jì)算結(jié)果除以所有分片的權(quán)重總和得到余數(shù)。該行會(huì)發(fā)送到那個(gè)包含該余數(shù)的從’prev_weight’到’prev_weights weight’的前閉后開區(qū)間對(duì)應(yīng)的分片上,其中 ‘prev_weights’ 是該分片前面的所有分片的權(quán)重和,‘weight’ 是該分片的權(quán)重。

分片表達(dá)式可以是由常量和表列組成的任何返回整數(shù)表達(dá)式。

下面的情況,需要關(guān)注分片方案:

  • 使用需要特定鍵連接數(shù)據(jù)( IN 或 JOIN )的查詢。如果數(shù)據(jù)是用該鍵進(jìn)行分片,則應(yīng)使用本地 IN 或 JOIN 而不是 GLOBAL IN 或 GLOBAL JOIN,這樣效率更高。
  • 使用大量服務(wù)器,但有大量小查詢,為了使小查詢不影響整個(gè)集群,讓單個(gè)客戶的數(shù)據(jù)處于單個(gè)分片上是有意義的?;蛘吣憧梢耘渲脙杉?jí)分片:將整個(gè)集群劃分為層,一個(gè)層可以包含多個(gè)分片。單個(gè)客戶的數(shù)據(jù)位于單個(gè)層上,根據(jù)需要將分片添加到層中,層中的數(shù)據(jù)隨機(jī)分布。然后給每層創(chuàng)建分布式表,再創(chuàng)建一個(gè)全局的分布式表用于全局的查詢。

Dictionary

可以將字典數(shù)據(jù)展示為一個(gè)ClickHouse的表。需要在XML配置文件中定義字典。官網(wǎng)文檔語(yǔ)焉不詳,更多介紹可見(jiàn)https://blog.csdn.net/vkingnew/article/details/106973674。

(不太好用的亞子)

Merge

本身不存儲(chǔ)數(shù)據(jù),但可用于同時(shí)從任意多個(gè)其他的表中讀取數(shù)據(jù)。 讀是自動(dòng)并行的,不支持寫入。讀取時(shí),那些被真正讀取到數(shù)據(jù)的表的索引(如果有的話)會(huì)被使用。

創(chuàng)建語(yǔ)法:

clickhouse使用入門(clickhouse使用教程)

如果tables_regexp命中了Merge 表本身,也不會(huì)真正引入,以免循環(huán)引用,但創(chuàng)建兩個(gè)表遞歸讀取對(duì)方數(shù)據(jù)是可行的。

Merge引擎的一個(gè)典型應(yīng)用是可以像使用一張表一樣使用大量的TinyLog表。

Executable和ExecutablePool

這兩個(gè)引擎用于關(guān)聯(lián)腳本和具體表,表中的數(shù)據(jù)將由執(zhí)行腳本后生成。腳本被放在”users_scripts”目錄下。創(chuàng)建表時(shí)不會(huì)立即調(diào)用腳本,腳本將在表被查詢時(shí)調(diào)用。

剛開始感覺(jué)這個(gè)引擎沒(méi)什么用,為什么我不直接單獨(dú)跑腳本把數(shù)據(jù)收集好之后再將它們插入表呢?轉(zhuǎn)念想到腳本代碼倉(cāng)庫(kù)里的幾百個(gè)(無(wú)名)腳本及對(duì)應(yīng)的(無(wú)名)表,瞬間感覺(jué)這功能還怪有用的。(查找表對(duì)應(yīng)的生成腳本)

(當(dāng)然,我沒(méi)用過(guò),等你去用)

應(yīng)用及可能的坑點(diǎn)

應(yīng)用

ClickHouse典型應(yīng)用場(chǎng)景主要包括以下幾個(gè)方面:

  1. 大數(shù)據(jù)存儲(chǔ)和分析:ClickHouse能夠高效地存儲(chǔ)和處理海量數(shù)據(jù),支持PB級(jí)別的數(shù)據(jù)存儲(chǔ)和分析,可以快速地處理大規(guī)模數(shù)據(jù)分析和數(shù)據(jù)挖掘任務(wù)。
  2. 實(shí)時(shí)數(shù)據(jù)分析和查詢:ClickHouse支持實(shí)時(shí)查詢和分析,具有高速的數(shù)據(jù)讀取和計(jì)算能力,可以在秒級(jí)別內(nèi)返回查詢結(jié)果,適用于需要快速響應(yīng)數(shù)據(jù)查詢和分析的業(yè)務(wù)場(chǎng)景。
  3. 日志處理和分析:ClickHouse能夠高效地處理日志數(shù)據(jù),支持實(shí)時(shí)的日志分析和查詢,可以幫助企業(yè)快速地發(fā)現(xiàn)和解決問(wèn)題。
  4. 業(yè)務(wù)智能分析:ClickHouse支持復(fù)雜的數(shù)據(jù)分析和計(jì)算,可以進(jìn)行高級(jí)的數(shù)據(jù)挖掘和機(jī)器學(xué)習(xí)算法,幫助企業(yè)進(jìn)行業(yè)務(wù)智能分析和決策。

總的來(lái)說(shuō),ClickHouse適用于需要處理大規(guī)模數(shù)據(jù)和實(shí)時(shí)查詢的業(yè)務(wù)場(chǎng)景,例如數(shù)據(jù)報(bào)表、日志分析、業(yè)務(wù)智能分析、廣告平臺(tái)等。

其他要說(shuō)的

part與partition:

這兩個(gè)概念,我覺(jué)得是ClickHouse文檔中容易搞混的一點(diǎn),特別中文文檔中出現(xiàn)的謎之概念『片段、片塊、部分、部件、分片』,如果不是原先就對(duì)ClickHouse有較深刻的認(rèn)識(shí),可能一時(shí)反應(yīng)不過(guò)來(lái)具體指代的是什么。關(guān)于這兩者的區(qū)別,在這個(gè)鏈接及頁(yè)面內(nèi)的鏈接中有較好的闡述。

關(guān)注ClickHouse版本:

ClickHouse的官方中文文檔相對(duì)英文文檔,內(nèi)容要稍微落后些(你說(shuō)跟俄文比如何?阿巴阿巴)。比如中文文檔中說(shuō)ClickHouse不支持窗口函數(shù),但英文文檔中表示已經(jīng)支持;中文文檔中沒(méi)有projection的介紹;中文文檔中表示ClickHouse使用ZooKeeper維護(hù)元數(shù)據(jù),然而在英文文檔中表示使用ClickHouse Keeper維護(hù)元數(shù)據(jù);等等等等。同樣的,你的生產(chǎn)環(huán)境的ClickHouse版本也許與ClickHouse最新版有不小差距,所以在你考慮使用某個(gè)功能時(shí),記得先看下當(dāng)前版本是否已經(jīng)支持。

關(guān)于ZooKeeper:

如上所述,ZooKeeper是ClickHouse常見(jiàn)版本的信息協(xié)調(diào)者。然而實(shí)際上一些行為日志也會(huì)存在其上,表的一些schema信息也會(huì)在上面做校驗(yàn)。而on cluster等操作也是依賴此實(shí)現(xiàn)的,在數(shù)據(jù)量較大時(shí)可能會(huì)有一些意外的阻塞情況發(fā)生,所以不要太依賴ClickHouse的on cluster等會(huì)依賴ZooKeeper的操作,能拿到具體節(jié)點(diǎn)的情況下,到每個(gè)節(jié)點(diǎn)上單獨(dú)執(zhí)行是更穩(wěn)妥的。作為國(guó)內(nèi)ClickHouse的布道者,宇宙條已經(jīng)替大家踩過(guò)相關(guān)的坑了(當(dāng)然我們團(tuán)隊(duì)也踩了一次)。

此外ClickHouse本身引擎對(duì)子查詢的SQL優(yōu)化效率不高,應(yīng)盡量避免復(fù)雜的子查詢語(yǔ)句。否則這些”cool cooler coolest”的SQL,在集群負(fù)載壓力逐漸上來(lái)之后,可能會(huì)變成半夜里響個(gè)不停的業(yè)務(wù)告警通知。

相關(guān)新聞

聯(lián)系我們
聯(lián)系我們
公眾號(hào)
公眾號(hào)
在線咨詢
分享本頁(yè)
返回頂部