「硬剛Doris系列」Doris高級(jí)用法

1.1 添加Rollup
Rollup 可以理解為 Table 的一個(gè)物化索引結(jié)構(gòu)。物化 是因?yàn)槠鋽?shù)據(jù)在物理上獨(dú)立存儲(chǔ),而 索引 的意思是,Rollup可以調(diào)整列順序以增加前綴索引的命中率,也可以減少key列以增加數(shù)據(jù)的聚合度。
以下舉例說明。
原表table1的Schema如下:
+----------+-------------+------+-------+---------+-------+
|?Field???|?Type???????|?Null?|?Key???|?Default?|?Extra?|
+----------+-------------+------+-------+---------+-------+
|?siteid???|?int(11)?????|?No???|?true?|?10?????|???????|
|?citycode?|?smallint(6)?|?No???|?true?|?N/A?????|???????|
|?username?|?varchar(32)?|?No???|?true?|?????????|???????|
|?pv???????|?bigint(20)?|?No???|?false?|?0???????|?SUM???|
|?uv???????|?bigint(20)?|?No???|?false?|?0???????|?SUM???|
+----------+-------------+------+-------+---------+-------+
對(duì)于 table1 明細(xì)數(shù)據(jù)是 siteid, citycode, username 三者構(gòu)成一組 key,從而對(duì) pv 字段進(jìn)行聚合;如果業(yè)務(wù)方經(jīng)常有看城市 pv 總量的需求,可以建立一個(gè)只有 citycode, pv 的rollup。
ALTER?TABLE?table1?ADD?ROLLUP?rollup_city(citycode,?pv);
1.2 Broadcast/Shuffle Join
系統(tǒng)默認(rèn)實(shí)現(xiàn) Join 的方式,是將小表進(jìn)行條件過濾后,將其廣播到大表所在的各個(gè)節(jié)點(diǎn)上,形成一個(gè)內(nèi)存 Hash 表,然后流式讀出大表的數(shù)據(jù)進(jìn)行Hash Join。但是如果當(dāng)小表過濾后的數(shù)據(jù)量無法放入內(nèi)存的話,此時(shí) Join 將無法完成,通常的報(bào)錯(cuò)應(yīng)該是首先造成內(nèi)存超限。
如果遇到上述情況,建議顯式指定 Shuffle Join,也被稱作 Partitioned Join。即將小表和大表都按照 Join 的 key 進(jìn)行 Hash,然后進(jìn)行分布式的 Join。這個(gè)對(duì)內(nèi)存的消耗就會(huì)分?jǐn)偟郊旱乃杏?jì)算節(jié)點(diǎn)上。
Doris會(huì)自動(dòng)嘗試進(jìn)行 Broadcast Join,如果預(yù)估小表過大則會(huì)自動(dòng)切換至 Shuffle Join。注意,如果此時(shí)顯式指定了 Broadcast Join 也會(huì)自動(dòng)切換至 Shuffle Join。
使用 Broadcast Join(默認(rèn)):
mysql>?select?sum(table1.pv)?from?table1?join?table2?where?table1.siteid?=?2;
+--------------------+
|?sum(`table1`.`pv`)?|
+--------------------+
|?????????????????10?|
+--------------------+
1?row?in?set?(0.20?sec)
使用 Broadcast Join(顯式指定):
mysql>?select?sum(table1.pv)?from?table1?join?[broadcast]?table2?where?table1.siteid?=?2;
+--------------------+
|?sum(`table1`.`pv`)?|
+--------------------+
|?????????????????10?|
+--------------------+
1?row?in?set?(0.20?sec)
使用 Shuffle Join:
mysql>?select?sum(table1.pv)?from?table1?join?[shuffle]?table2?where?table1.siteid?=?2;
+--------------------+
|?sum(`table1`.`pv`)?|
+--------------------+
|?????????????????10?|
+--------------------+
1?row?in?set?(0.15?sec)
1.3 Colocation Join
1.3.1 名詞解釋
FE:Frontend,Doris 的前端節(jié)點(diǎn)。負(fù)責(zé)元數(shù)據(jù)管理和請(qǐng)求接入。
BE:Backend,Doris 的后端節(jié)點(diǎn)。負(fù)責(zé)查詢執(zhí)行和數(shù)據(jù)存儲(chǔ)。
Colocation Group(CG):一個(gè) CG 中會(huì)包含一張及以上的 Table。在同一個(gè) Group 內(nèi)的 Table 有著相同的 Colocation Group Schema,并且有著相同的數(shù)據(jù)分片分布。
Colocation Group Schema(CGS):用于描述一個(gè) CG 中的 Table,和 Colocation 相關(guān)的通用 Schema 信息。包括分桶列類型,分桶數(shù)以及副本數(shù)等。
1.3.2 原理
doris 除了支持Broadcast/Shuffle Join 之外,Colocation Join更是一大特色。Colocation Join 功能,是將一組擁有相同 CGS 的 Table 組成一個(gè) CG。并保證這些 Table 對(duì)應(yīng)的數(shù)據(jù)分片會(huì)落在同一個(gè) BE 節(jié)點(diǎn)上。使得當(dāng) CG 內(nèi)的表進(jìn)行分桶列上的 Join 操作時(shí),可以通過直接進(jìn)行本地?cái)?shù)據(jù) Join,減少數(shù)據(jù)在節(jié)點(diǎn)間的傳輸耗時(shí)。
為了使得 Table 能夠有相同的數(shù)據(jù)分布,同一 CG 內(nèi)的 Table 必須保證以下屬性相同:
分桶列和分桶數(shù)
分桶列,即在建表語句中 DISTRIBUTED BY HASH(col1, col2, ...) 中指定的列。分桶列決定了一張表的數(shù)據(jù)通過哪些列的值進(jìn)行 Hash 劃分到不同的 Tablet 中。同一 CG 內(nèi)的 Table 必須保證分桶列的類型和數(shù)量完全一致,并且桶數(shù)一致,才能保證多張表的數(shù)據(jù)分片能夠一一對(duì)應(yīng)的進(jìn)行分布控制。副本數(shù)
同一個(gè) CG 內(nèi)所有表的所有分區(qū)(Partition)的副本數(shù)必須一致。如果不一致,可能出現(xiàn)某一個(gè) Tablet 的某一個(gè)副本,在同一個(gè) BE 上沒有其他的表分片的副本對(duì)應(yīng)。
同一個(gè) CG 內(nèi)的表,分區(qū)的個(gè)數(shù)、范圍以及分區(qū)列的類型不要求一致。
1.3.3 舉例說明
CREATE?TABLE?`tbl1`?(
????`k1`?date?NOT?NULL?COMMENT?"",
????`k2`?int(11)?NOT?NULL?COMMENT?"",
????`v1`?int(11)?SUM?NOT?NULL?COMMENT?""
)?ENGINE=OLAP
AGGREGATE?KEY(`k1`,?`k2`)
PARTITION?BY?RANGE(`k1`)
(
????PARTITION?p1?VALUES?LESS?THAN?('2019-05-31'),
????PARTITION?p2?VALUES?LESS?THAN?('2019-06-30')
)
DISTRIBUTED?BY?HASH(`k2`)?BUCKETS?8
PROPERTIES?(
????"colocate_with"?=?"group1"
);
CREATE?TABLE?`tbl2`?(
????`k1`?datetime?NOT?NULL?COMMENT?"",
????`k2`?int(11)?NOT?NULL?COMMENT?"",
????`v1`?double?SUM?NOT?NULL?COMMENT?""
)?ENGINE=OLAP
AGGREGATE?KEY(`k1`,?`k2`)
DISTRIBUTED?BY?HASH(`k2`)?BUCKETS?8
PROPERTIES?(
????"colocate_with"?=?"group1"
);
查看查詢計(jì)劃,如果 Colocation Join 生效,則 Hash Join 節(jié)點(diǎn)會(huì)顯示 colocate: true。
DESC?SELECT?*?FROM?tbl1?INNER?JOIN?tbl2?ON?(tbl1.k2?=?tbl2.k2);
+----------------------------------------------------+
|?Explain?String?????????????????????????????????????|
+----------------------------------------------------+
|?PLAN?FRAGMENT?0????????????????????????????????????|
|??OUTPUT?EXPRS:`tbl1`.`k1`?|????????????????????????|
|???PARTITION:?RANDOM????????????????????????????????|
|????????????????????????????????????????????????????|
|???RESULT?SINK??????????????????????????????????????|
|????????????????????????????????????????????????????|
|???2:HASH?JOIN??????????????????????????????????????|
|???|??join?op:?INNER?JOIN???????????????????????????|
|???|??hash?predicates:??????????????????????????????|
|???|??colocate:?true????????????????????????????????|
|???|????`tbl1`.`k2`?=?`tbl2`.`k2`???????????????????|
|???|??tuple?ids:?0?1????????????????????????????????|
|???|????????????????????????????????????????????????|
|???|----1:OlapScanNode??????????????????????????????|
|???|???????TABLE:?tbl2??????????????????????????????|
|???|???????PREAGGREGATION:?OFF.?Reason:?null????????|
|???|???????partitions=0/1???????????????????????????|
|???|???????rollup:?null?????????????????????????????|
|???|???????buckets=0/0??????????????????????????????|
|???|???????cardinality=-1???????????????????????????|
|???|???????avgRowSize=0.0???????????????????????????|
|???|???????numNodes=0???????????????????????????????|
|???|???????tuple?ids:?1?????????????????????????????|
|???|????????????????????????????????????????????????|
|???0:OlapScanNode???????????????????????????????????|
|??????TABLE:?tbl1???????????????????????????????????|
|??????PREAGGREGATION:?OFF.?Reason:?No?AggregateInfo?|
|??????partitions=0/2????????????????????????????????|
|??????rollup:?null??????????????????????????????????|
|??????buckets=0/0???????????????????????????????????|
|??????cardinality=-1????????????????????????????????|
|??????avgRowSize=0.0????????????????????????????????|
|??????numNodes=0????????????????????????????????????|
|??????tuple?ids:?0??????????????????????????????????|
+----------------------------------------------------+
1.4 動(dòng)態(tài)分區(qū)
1.4.1 原理
在某些使用場(chǎng)景下,用戶會(huì)將表按照天進(jìn)行分區(qū)劃分,每天定時(shí)執(zhí)行例行任務(wù),這時(shí)需要使用方手動(dòng)管理分區(qū),否則可能由于使用方?jīng)]有創(chuàng)建分區(qū)導(dǎo)致數(shù)據(jù)導(dǎo)入失敗,這給使用方帶來了額外的維護(hù)成本。
在實(shí)現(xiàn)方式上, FE會(huì)啟動(dòng)一個(gè)后臺(tái)線程,根據(jù)fe.conf中dynamic_partition_enable 及 dynamic_partition_check_interval_seconds參數(shù)決定該線程是否啟動(dòng)以及該線程的調(diào)度頻率。每次調(diào)度時(shí),會(huì)在注冊(cè)表中讀取動(dòng)態(tài)分區(qū)表的屬性,并根據(jù)動(dòng)態(tài)分區(qū)屬性動(dòng)態(tài)添加及刪除分區(qū)。
1.4.2 舉例說明
建表時(shí),可以在 PROPERTIES 中指定以下dynamic_partition屬性,表示這個(gè)表是一個(gè)動(dòng)態(tài)分區(qū)表。
CREATE?TABLE?example_db.dynamic_partition
(
k1?DATE,
k2?INT,
k3?SMALLINT,
v1?VARCHAR(2048),
v2?DATETIME?DEFAULT?"2014-02-04?15:36:00"
)
ENGINE=olap
DUPLICATE?KEY(k1,?k2,?k3)
PARTITION?BY?RANGE?(k1)
(
PARTITION?p20200321?VALUES?LESS?THAN?("2020-03-22"),
PARTITION?p20200322?VALUES?LESS?THAN?("2020-03-23"),
PARTITION?p20200323?VALUES?LESS?THAN?("2020-03-24"),
PARTITION?p20200324?VALUES?LESS?THAN?("2020-03-25")
)
DISTRIBUTED?BY?HASH(k2)?BUCKETS?32
PROPERTIES(
"storage_medium"?=?"SSD",
"dynamic_partition.enable"?=?"true",
"dynamic_partition.time_unit"?=?"DAY",
"dynamic_partition.start"?=?"-3",
"dynamic_partition.end"?=?"3",
"dynamic_partition.prefix"?=?"p",
"dynamic_partition.buckets"?=?"32"
?);
創(chuàng)建一張動(dòng)態(tài)分區(qū)表,指定開啟動(dòng)態(tài)分區(qū)特性,以當(dāng)天為2020-03-25為例,在每次調(diào)度時(shí),會(huì)刪除分區(qū)上界小于 2020-03-22 的分區(qū),為了避免刪除非動(dòng)態(tài)創(chuàng)建的分區(qū),動(dòng)態(tài)刪除分區(qū)只會(huì)刪除分區(qū)名符合動(dòng)態(tài)創(chuàng)建分區(qū)規(guī)則的分區(qū),例如分區(qū)名為a1, 則即使分區(qū)范圍在待刪除的分區(qū)范圍內(nèi),也不會(huì)被刪除。同時(shí)在調(diào)度時(shí)會(huì)提前創(chuàng)建今天以及以后3天(總共4天)的分區(qū)(若分區(qū)已存在則會(huì)忽略),分區(qū)名根據(jù)指定前綴分別為p20200325 p20200326p20200327 p20200328,每個(gè)分區(qū)的分桶數(shù)量為32。同時(shí)會(huì)刪除 p20200321 的分區(qū)。
1.4.3 分區(qū)屬性參數(shù)
dynamic_partition.enable: 是否開啟動(dòng)態(tài)分區(qū)特性,可指定為 TRUE 或 FALSE。如果不填寫,默認(rèn)為 TRUE。
dynamic_partition.time_unit: 動(dòng)態(tài)分區(qū)調(diào)度的單位,可指定為 DAY WEEK MONTH,當(dāng)指定為 DAY時(shí),動(dòng)態(tài)創(chuàng)建的分區(qū)名后綴格式為yyyyMMdd,例如20200325。當(dāng)指定為 WEEK 時(shí),動(dòng)態(tài)創(chuàng)建的分區(qū)名后綴格式為yyyy_ww即當(dāng)前日期屬于這一年的第幾周,例如 2020-03-25 創(chuàng)建的分區(qū)名后綴為 2020_13, 表明目前為2020年第13周。當(dāng)指定為 MONTH 時(shí),動(dòng)態(tài)創(chuàng)建的分區(qū)名后綴格式為 yyyyMM,例如 202003。
dynamic_partition.start: 動(dòng)態(tài)分區(qū)的開始時(shí)間, 以當(dāng)天為基準(zhǔn),超過該時(shí)間范圍的分區(qū)將會(huì)被刪除。如果不填寫,則默認(rèn)為Integer.MIN_VALUE 即 -2147483648。
dynamic_partition.end: 動(dòng)態(tài)分區(qū)的結(jié)束時(shí)間, 以當(dāng)天為基準(zhǔn),會(huì)提前創(chuàng)建N個(gè)單位的分區(qū)范圍。
dynamic_partition.prefix: 動(dòng)態(tài)創(chuàng)建的分區(qū)名前綴。
dynamic_partition.buckets: 動(dòng)態(tài)創(chuàng)建的分區(qū)所對(duì)應(yīng)的分桶數(shù)量。
1.5 支持Bitmap
使用 Roaring Bitmap 數(shù)據(jù)結(jié)構(gòu),現(xiàn)場(chǎng)查詢時(shí)的 IO,CPU,內(nèi)存,網(wǎng)絡(luò)資源會(huì)顯著減少,并且不會(huì)隨著數(shù)據(jù)規(guī)模線性增加。
CREATE?TABLE?`pv_bitmap`?(
`dt`?int,
`page`?varchar(10),
`user_id`?bitmap?bitmap_union
)
AGGREGATE?KEY(`dt`,?page)
DISTRIBUTED?BY?HASH(`dt`)?BUCKETS?2;
select?bitmap_count(bitmap_union(user_id))?from?pv_bitmap;?
select?bitmap_union_count(user_id)?from?pv_bitmap;
select?bitmap_union_int(id)?from?pv_bitmap;?
BITMAP_UNION(expr)?:?計(jì)算兩個(gè)?Bitmap?的并集,返回值是序列化后的?Bitmap?值?
BITMAP_COUNT(expr)?:?計(jì)算?Bitmap?的基數(shù)值?
BITMAP_UNION_COUNT(expr):?和?BITMAP_COUNT(BITMAP_UNION(expr))?等價(jià)?
BITMAP_UNION_INT(expr)?:?和?COUNT(DISTINCT?expr)?等價(jià)?(僅支持?TINYINT,SMALLINT?和?INT)
1.6 物化視圖
物化視圖是將預(yù)先計(jì)算(根據(jù)定義好的 SELECT 語句)好的數(shù)據(jù)集,存儲(chǔ)在 Doris 中的一個(gè)特殊的表。
物化視圖的出現(xiàn)主要是為了滿足用戶,既能對(duì)原始明細(xì)數(shù)據(jù)的任意維度分析,也能快速的對(duì)固定維度進(jìn)行分析查詢。
在沒有物化視圖功能之前,用戶一般都是使用 Rollup 功能通過預(yù)聚合方式提升查詢效率的。但是 Rollup 具有一定的局限性,他不能基于明細(xì)模型做預(yù)聚合。
物化視圖則在覆蓋了 Rollup 的功能的同時(shí),還能支持更豐富的聚合函數(shù)。所以物化視圖其實(shí)是 Rollup 的一個(gè)超集。
也就是說,之前 ALTER TABLE ADD ROLLUP 語法支持的功能現(xiàn)在均可以通過 CREATE MATERIALIZED VIEW 實(shí)現(xiàn)。
create?materialized?view?store_amt?as
select?store_id,?sum(sale_amt)?from?sales_records?group?by?store_id;

2022年全網(wǎng)首發(fā)|大數(shù)據(jù)專家級(jí)技能模型與學(xué)習(xí)指南(勝天半子篇)
