一、doris是什么
Apache Doris是一個現代化的MPP(大規模並行分析)分析型數據庫產品。僅需亞秒級響應時間即可獲得查詢結果,有效地支持實時數據分析。Apache Doris的分布式架構非常簡潔,易於運維,並且可以支持10PB以上的超大數據集。
Apache Doris可以滿足多種數據分析需求,例如固定歷史報表,實時數據分析,交互式數據分析和探索式數據分析等。令數據分析工作更加簡單高效!
二、數據模型
-
Aggregate(聚合模型,提前聚合數據, 適合報表和多維分析業務)
- SUM:求和,多行的 Value 進行累加。
- REPLACE:替代,下一批數據中的 Value 會替換之前導入過的行中的 Value。
- MAX:保留最大值。
-
MIN:保留最小值。
CREATE TABLE IF NOT EXISTS example_db.expamle_tbl ( `user_id` LARGEINT NOT NULL COMMENT "用戶id", `date` DATE NOT NULL COMMENT "數據灌入日期時間", `city` VARCHAR(20) COMMENT "用戶所在城市", `age` SMALLINT COMMENT "用戶年齡", `sex` TINYINT COMMENT "用戶性別", `last_visit_date` DATETIME REPLACE DEFAULT "1970-01-01 00:00:00" COMMENT "用戶最后一次訪問時間", `cost` BIGINT SUM DEFAULT "0" COMMENT "用戶總消費", `max_dwell_time` INT MAX DEFAULT "0" COMMENT "用戶最大停留時間", `min_dwell_time` INT MIN DEFAULT "99999" COMMENT "用戶最小停留時間", ) AGGREGATE KEY(`user_id`, `date`, `timestamp`, `city`, `age`, `sex`) ... /* 省略 Partition 和 Distribution 信息 */ ;
user_id date city age sex last_visit_date cost max_dwell_time min_dwell_time 10000 2017-10-01 北京 20 0 2017-10-01 06:00:00 20 10 10 10000 2017-10-01 北京 20 0 2017-10-01 07:00:00 15 2 2 在導入上述數據時,最終表里面就只有一行數據:
user_id date city age sex last_visit_date cost max_dwell_time min_dwell_time 10000 2017-10-01 北京 20 0 2017-10-01 07:00:00 35 10 2 其中user_id, date, city age,sex 因為沒有聚合模型,因此只有當他們都一樣時,才可以發生后面的聚合;假設city不一樣就不能聚合;
- 如果業務場景就是需要存入明細,那么一般的做法是列增加時間戳,這樣每一列都不一樣,就可以保存數據明細;
- 數據在不同時間,可能聚合的程度不一致。比如一批數據剛導入時,可能還未與之前已存在的數據進行聚合。但是對於用戶而言,用戶只能查詢到聚合后的數據。即不同的聚合程度對於用戶查詢而言是透明的。用戶需始終認為數據以最終的完成的聚合程度存在,而不應假設某些聚合還未發生。
-
Uniq模型(保證 Key 的唯一性,適用於有更新需求的分析業務。)
- 其實是Aggregate聚合模型的一個特例,即只有aggregate key 是唯一的,其他列都是replace特性
-
CREATE TABLE IF NOT EXISTS example_db.expamle_tbl ( `user_id` LARGEINT NOT NULL COMMENT "用戶id", `username` VARCHAR(50) NOT NULL COMMENT "用戶昵稱", `city` VARCHAR(20) COMMENT "用戶所在城市", `age` SMALLINT COMMENT "用戶年齡", `sex` TINYINT COMMENT "用戶性別", `phone` LARGEINT COMMENT "用戶電話", `address` VARCHAR(500) COMMENT "用戶地址", `register_time` DATETIME COMMENT "用戶注冊時間" ) UNIQUE KEY(`user_id`, `user_name`)
等同於:
-
CREATE TABLE IF NOT EXISTS example_db.expamle_tbl ( `user_id` LARGEINT NOT NULL COMMENT "用戶id", `username` VARCHAR(50) NOT NULL COMMENT "用戶昵稱", `city` VARCHAR(20) REPLACE COMMENT "用戶所在城市", `age` SMALLINT REPLACE COMMENT "用戶年齡", `sex` TINYINT REPLACE COMMENT "用戶性別", `phone` LARGEINT REPLACE COMMENT "用戶電話", `address` VARCHAR(500) REPLACE COMMENT "用戶地址", `register_time` DATETIME REPLACE COMMENT "用戶注冊時間" ) AGGREGATE KEY(`user_id`, `user_name`)
-
Duplicate模型(只指定排序列,相同的行不會合並。適用於數據無需提前聚合的分析業務。)
CREATE TABLE IF NOT EXISTS example_db.expamle_tbl ( `timestamp` DATETIME NOT NULL COMMENT "日志時間", `type` INT NOT NULL COMMENT "日志類型", `error_code` INT COMMENT "錯誤碼", `error_msg` VARCHAR(1024) COMMENT "錯誤詳細信息", `op_id` BIGINT COMMENT "負責人id", `op_time` DATETIME COMMENT "處理時間" ) DUPLICATE KEY(`timestamp`, `type`)
這種數據模型區別於 Aggregate 和 Uniq 模型。數據完全按照導入文件中的數據進行存儲,不會有任何聚合。即使兩行數據完全相同,也都會保留。 而在建表語句中指定的 DUPLICATE KEY,只是用來指明底層數據按照那些列進行排序。
三、ROLLUP(上面的每個模型產生的其實是一個base表,我們需要在base表的基礎上建立其他表,以便於提高查詢效率)
Rollup 本質上可以理解為原始表(Base Table)的一個物化索引。建立 Rollup 時可只選取 Base Table 中的部分列作為 Schema。Schema 中的字段順序也可與 Base Table 不同
表存儲數據如下:
| user_id | date | timestamp | city | age | sex | last_visit_date | cost | max_dwell_time | min_dwell_time |
|---|---|---|---|---|---|---|---|---|---|
| 10000 | 2017-10-01 | 2017-10-01 08:00:05 | 北京 | 20 | 0 | 2017-10-01 06:00:00 | 20 | 10 | 10 |
| 10000 | 2017-10-01 | 2017-10-01 09:00:05 | 北京 | 20 | 0 | 2017-10-01 07:00:00 | 15 | 2 | 2 |
| 10001 | 2017-10-01 | 2017-10-01 18:12:10 | 北京 | 30 | 1 | 2017-10-01 17:05:45 | 2 | 22 | 22 |
在此基礎上,我們創建一個 ROLLUP:
| ColumnName |
|---|
| user_id |
| cost |
創建完成后,表里面的數據為
| user_id | cost |
|---|---|
| 10000 | 35 |
| 10001 | 2 |
這個時候我們如果查詢SELECT user_id, sum(cost) FROM table GROUP BY user_id; 則doris會自動命中這個 ROLLUP 表,從而只需掃描極少的數據量,即可完成這次聚合查詢;
rollup重要特點:
· ROLLUP 是附屬於 Base 表的,可以看做是 Base 表的一種輔助數據結構。用戶可以在 Base 表的基礎上,創建或刪除 ROLLUP,但是不能在查詢中顯式的指定查詢某 ROLLUP。是否命中 ROLLUP 完全由 Doris 系統自動決定。 · ROLLUP 的數據是獨立物理存儲的。因此,創建的 ROLLUP 越多,占用的磁盤空間也就越大。同時對導入速度也會有影響,但是不會降低查詢效率; · ROLLUP 的數據更新與 Base 表示完全同步的; · 查詢能否命中 ROLLUP 的一個必要條件(非充分條件)是,查詢所涉及的所有列(包括 select list 和 where 中的查詢條件列等)都存在於該 ROLLUP 的列中。否則,查詢只能命中 Base 表。
四、join操作(hash join,broadcast join,shuffle join )
Join是數據庫查詢永遠繞不開的話題,傳統查詢SQL技術總體可以分為簡單操作(過濾操作-where、排序操作-limit等),聚合操作-groupBy等以及Join操作等。其中Join操作是其中最復雜、代價最大的操作類型
傳統數據庫單機模式做Join的場景畢竟有限,也建議盡量減少使用Join。然而大數據領域就完全不同,Join是標配,OLAP業務根本無法離開表與表之間的關聯,對Join的支持成熟度一定程度上決定了系統的性能,誇張點說,“得Join者得天下”
Doris會自動嘗試進行 Broadcast Join,如果預估小表過大則會自動切換至 Shuffle Join。注意,如果此時顯式指定了 Broadcast Join 也會自動切換至 Shuffle Join。
- hash join算法就來自於傳統數據庫,而shuffle和broadcast是大數據的皮,兩者一結合就成了大數據的算法了
- hash join: 適用於至少有一個是小表的場景(hash join基本都只掃描兩表一次,可以認為O(a+b),較之最極端的是笛卡爾積運算O(a*b), 小表的原因是在構建Hash Table時,最好可以把數據全部加載到內存中,因為這樣效率才最高)
- 兩個表,取小表為Build Table, 大表為Probe Table
- 構建Hash Table:依次讀取Build Table的數據,對於每一條數據根據Join Key進行hash,hash到對應的bucket中(類似於HashMap的原理),最后會生成一張HashTable,HashTable會緩存在內存中,如果內存放不下會dump到磁盤中;
-
匹配:生成Hash Table后,在依次掃描Probe Table的數據,使用相同的hash函數(在spark中,實際上就是要使用相同的partitioner)在Hash Table中尋找hash(join key)相同的值,如果匹配成功就將兩者join在一起。
- broadcast join(將其中一張較小的表通過廣播的方式,由driver發送到各個executor,大表正常被分成多個區,每個分區的數據和本地的廣播變量進行join(相當於每個executor上都有一份小表的數據,並且這份數據是在內存中的,過來的分區中的數據和這份數據進行join)。broadcast適用於表很小,可以直接被廣播的場景;)
- 基表不能被廣播,比如left outer join時,只能廣播右表
- shuffle join(一旦小表比較大,此時就不適合使用broadcast hash join了。這種情況下,可以對兩張表分別進行shuffle,將兩張表相同key的數據分到一個分區中,然后分區和分區之間進行join。相當於將兩張表都分成了若干小份,小份和小份之間進行hash join,充分利用集群資源。)
五、分區& 分桶
Doris 支持兩級分區存儲, 第一層為 RANGE 分區(partition), 第二層為 HASH 分桶(bucket)
RANGE分區用於將數據划分成不同區間, 邏輯上可以理解為將原始表划分成了多個子表。業務上,多數用戶會選擇采用按時間進行partition, 讓時間進行partition有以下好處:
* 可區分冷熱數據
* 可用上Doris分級存儲(SSD + SATA)的功能
* 按分區刪除數據時,更加迅速-
根據hash值將數據划分成不同的 bucket。* 建議采用區分度大的列做分桶, 避免出現數據傾斜 * 為方便數據恢復, 建議單個 bucket 的 size 不要太大, 保持在 10GB 以內, 所以建表或增加 partition 時請合理考慮 bucket 數目, 其中不同 partition 可指定不同的 buckets 數。
多字段的分區鍵比較是基於數組的比較。它先用插入的數據的第一個字段值和分區的第一個值進行比較,如果插入的第一個值小於分區的第一個值那么就不需要比較第二個值就屬於該分區;如果第一個值等於分區的第一個值,開始比較第二個值同樣如果第二個值小於分區的第二個值那么就屬於該分區。
六、數倉分層
doris庫的表是有幾種不同前綴的, 每一種前綴其實是代表了不同的數據分層;
- ods層:最原始的數據,比如日志, 數據保持原有數據格式不變;
- dwd層:對ods層的數據進行清洗,比如去除掉一些臟數據,空值等;
- dws層:在dwd層的基礎上,進行聚合,形成寬表,比如續報信息,會有新報、先報、續報等信息;寬表:一張表會涵蓋比較多的業務內容,由於其字段較多,因此一般也會稱該層的表為寬表,寬表缺點是數據會有大量冗余,而且生成相對比較滯后,查詢結果可能並不及時。
- Schema 中字段數比較多, 聚合模型中可能 key 列比較多, 導入過程中需要排序的列會增加。
- 維度信息更新會反應到整張表中,而更新的頻率直接影響查詢的效率。
- ads層:為各種統計報表提供數據;比如ads_ws_renew就是提供續報的相關數據;
- dim:維表, 比如dim_course_info就是課程信息;維表分為:高基數維度數據:一般是用戶資料表、商品資料表類似的資料表,數據量可能是千萬級或者上億級別;低基數維度數據:一般是配置表,比如枚舉值對應的中文含義,或者日期維表。數據量可能是個位數或者幾千幾萬
