中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Apache Doris數據模型的介紹

發布時間:2021-06-23 15:07:39 來源:億速云 閱讀:841 作者:chen 欄目:大數據

這篇文章主要介紹“Apache Doris數據模型的介紹”,在日常操作中,相信很多人在Apache Doris數據模型的介紹問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”Apache Doris數據模型的介紹”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!

基本概念

在 Doris 中,數據以表(Table)的形式進行邏輯上的描述。 一張表包括行(Row)和列(Column)。Row 即用戶的一行數據。Column 用于描述一行數據中不同的字段。

Column 可以分為兩大類:Key 和 Value。從業務角度看,Key 和 Value 可以分別對應維度列和指標列。

Doris 的數據模型主要分為3類:

  • Duplicate 明細模型

  • Aggregate 聚合模型

  • Unique 唯一主鍵模型

下面我們分別介紹。

Duplicate 明細模型

明細模型是 Doris 默認使用的數據模型。該數據模型不會對導入的數據進行任何處理。表中的數據即用戶導入的原始數據。

ColumnNameTypeSortKeyComment
timestampDATETIMEYes日志時間
typeINTYes日志類型
error_codeINTYes錯誤碼
error_msgVARCHAR(1024)No錯誤詳細信息
op_idBIGINTNo負責人id
op_timeDATETIMENo處理時間

建表語句如下:

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`)
... /* 省略 Partition 和 Distribution 信息 */
;

建表語句中指定的 DUPLICATE KEY,只是用來指明底層數據按照那些列進行排序。(更貼切的名稱應該為 “Sorted Column”,這里取名 “DUPLICATE KEY” 只是用以明確表示所用的數據模型。關于 “Sorted Column”的更多解釋,索引文檔)。在 DUPLICATE KEY 的選擇上,我們建議適當的選擇前 2-4 列就可以。

這種數據模型適用于既沒有聚合需求,又沒有主鍵唯一性約束的原始數據的存儲。同時,用戶也可以通過物化視圖功能功能在這種模型基礎上建立聚合視圖,因此是一種比較推薦的數據模型。

Aggregate 聚合模型

聚合模型需要用戶在建表時顯式的將列分為 Key 列和 Value 列。該模型會自動的對 Key 相同的行,在 Value 列上進行聚合操作。

我們以實際的例子來說明什么是聚合模型,以及如何正確的使用聚合模型。

示例1:導入數據聚合

假設業務有如下數據表模式:

ColumnNameTypeAggregationTypeComment
user_idLARGEINT
用戶id
dateDATE
數據灌入日期
cityVARCHAR(20)
用戶所在城市
ageSMALLINT
用戶年齡
sexTINYINT
用戶性別
last_visit_dateDATETIMEREPLACE用戶最后一次訪問時間
costBIGINTSUM用戶總消費
max_dwell_timeINTMAX用戶最大停留時間
min_dwell_timeINTMIN用戶最小停留時間

如果轉換成建表語句則如下(省略建表語句中的 Partition 和 Distribution 信息)

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 信息 */
;

可以看到,這是一個典型的用戶信息和訪問行為的事實表。 在一般星型模型中,用戶信息和訪問行為一般分別存放在維度表和事實表中。這里我們為了更加方便的解釋 Doris 的數據模型,將兩部分信息統一存放在一張表中。

表中的列按照是否設置了 AggregationType,分為 Key (維度列) 和 Value(指標列)。沒有設置 AggregationType 的,如 user_iddateage ... 等稱為 Key,而設置了 AggregationType 的稱為 Value

當我們導入數據時,對于 Key 列相同的行會聚合成一行,而 Value 列會按照設置的 AggregationType 進行聚合。 AggregationType 目前有以下四種聚合方式:

  1. SUM:求和,多行的 Value 進行累加。

  2. REPLACE:替代,下一批數據中的 Value 會替換之前導入過的行中的 Value。

  3. MAX:保留最大值。

  4. MIN:保留最小值。

假設我們有以下導入數據(原始數據):

user_iddatecityagesexlast_visit_datecostmax_dwell_timemin_dwell_time
100002017-10-01北京2002017-10-01 06:00:00201010
100002017-10-01北京2002017-10-01 07:00:001522
100012017-10-01北京3012017-10-01 17:05:4522222
100022017-10-02上海2012017-10-02 12:59:1220055
100032017-10-02廣州3202017-10-02 11:20:00301111
100042017-10-01深圳3502017-10-01 10:00:1510033
100042017-10-03深圳3502017-10-03 10:20:221166

我們假設這是一張記錄用戶訪問某商品頁面行為的表。我們以第一行數據為例,解釋如下:

數據說明
10000用戶id,每個用戶唯一識別id
2017-10-01數據入庫時間,精確到日期
北京用戶所在城市
20用戶年齡
0性別男(1 代表女性)
2017-10-01 06:00:00用戶本次訪問該頁面的時間,精確到秒
20用戶本次訪問產生的消費
10用戶本次訪問,駐留該頁面的時間
10用戶本次訪問,駐留該頁面的時間(冗余)

那么當這批數據正確導入到 Doris 中后,Doris 中最終存儲如下:

user_iddatecityagesexlast_visit_datecostmax_dwell_timemin_dwell_time
100002017-10-01北京2002017-10-01 07:00:0035102
100012017-10-01北京3012017-10-01 17:05:4522222
100022017-10-02上海2012017-10-02 12:59:1220055
100032017-10-02廣州3202017-10-02 11:20:00301111
100042017-10-01深圳3502017-10-01 10:00:1510033
100042017-10-03深圳3502017-10-03 10:20:221166

可以看到,用戶 10000 只剩下了一行聚合后的數據。而其余用戶的數據和原始數據保持一致。這里先解釋下用戶 10000 聚合后的數據:

前5列沒有變化,從第6列 last_visit_date 開始:

  • 2017-10-01 07:00:00:因為 last_visit_date 列的聚合方式為 REPLACE,所以 2017-10-01 07:00:00 替換了 2017-10-01 06:00:00 保存了下來。

    注:在同一個導入批次中的數據,對于 REPLACE 這種聚合方式,替換順序不做保證。如在這個例子中,最終保存下來的,也有可能是 2017-10-01 06:00:00。而對于不同導入批次中的數據,可以保證,后一批次的數據會替換前一批次。

  • 35:因為 cost 列的聚合類型為 SUM,所以由 20 + 15 累加獲得 35。

  • 10:因為 max_dwell_time 列的聚合類型為 MAX,所以 10 和 2 取最大值,獲得 10。

  • 2:因為 min_dwell_time 列的聚合類型為 MIN,所以 10 和 2 取最小值,獲得 2。

經過聚合,Doris 中最終只會存儲聚合后的數據。換句話說,即明細數據會丟失,用戶不能夠再查詢到聚合前的明細數據了。

示例2:保留明細數據

接示例1,我們將表結構修改如下:

ColumnNameTypeAggregationTypeComment
user_idLARGEINT
用戶id
dateDATE
數據灌入日期
timestampDATETIME
數據灌入時間,精確到秒
cityVARCHAR(20)
用戶所在城市
ageSMALLINT
用戶年齡
sexTINYINT
用戶性別
last_visit_dateDATETIMEREPLACE用戶最后一次訪問時間
costBIGINTSUM用戶總消費
max_dwell_timeINTMAX用戶最大停留時間
min_dwell_timeINTMIN用戶最小停留時間

即增加了一列 timestamp,記錄精確到秒的數據灌入時間。

導入數據如下:

user_iddatetimestampcityagesexlast_visit_datecostmax_dwell_timemin_dwell_time
100002017-10-012017-10-01 08:00:05北京2002017-10-01 06:00:00201010
100002017-10-012017-10-01 09:00:05北京2002017-10-01 07:00:001522
100012017-10-012017-10-01 18:12:10北京3012017-10-01 17:05:4522222
100022017-10-022017-10-02 13:10:00上海2012017-10-02 12:59:1220055
100032017-10-022017-10-02 13:15:00廣州3202017-10-02 11:20:00301111
100042017-10-012017-10-01 12:12:48深圳3502017-10-01 10:00:1510033
100042017-10-032017-10-03 12:38:20深圳3502017-10-03 10:20:221166

那么當這批數據正確導入到 Doris 中后,Doris 中最終存儲如下:

user_iddatetimestampcityagesexlast_visit_datecostmax_dwell_timemin_dwell_time
100002017-10-012017-10-01 08:00:05北京2002017-10-01 06:00:00201010
100002017-10-012017-10-01 09:00:05北京2002017-10-01 07:00:001522
100012017-10-012017-10-01 18:12:10北京3012017-10-01 17:05:4522222
100022017-10-022017-10-02 13:10:00上海2012017-10-02 12:59:1220055
100032017-10-022017-10-02 13:15:00廣州3202017-10-02 11:20:00301111
100042017-10-012017-10-01 12:12:48深圳3502017-10-01 10:00:1510033
100042017-10-032017-10-03 12:38:20深圳3502017-10-03 10:20:221166

我們可以看到,存儲的數據,和導入數據完全一樣,沒有發生任何聚合。這是因為,這批數據中,因為加入了 timestamp 列,所有行的 Key 都不完全相同。也就是說,只要保證導入的數據中,每一行的 Key 都不完全相同,那么即使在聚合模型下,Doris 也可以保存完整的明細數據。

示例3:導入數據與已有數據聚合

接示例1。假設現在表中已有數據如下:

user_iddatecityagesexlast_visit_datecostmax_dwell_timemin_dwell_time
100002017-10-01北京2002017-10-01 07:00:0035102
100012017-10-01北京3012017-10-01 17:05:4522222
100022017-10-02上海2012017-10-02 12:59:1220055
100032017-10-02廣州3202017-10-02 11:20:00301111
100042017-10-01深圳3502017-10-01 10:00:1510033
100042017-10-03深圳3502017-10-03 10:20:221166

我們再導入一批新的數據:

user_iddatecityagesexlast_visit_datecostmax_dwell_timemin_dwell_time
100042017-10-03深圳3502017-10-03 11:22:00441919
100052017-10-03長沙2912017-10-03 18:11:02311

那么當這批數據正確導入到 Doris 中后,Doris 中最終存儲如下:

user_iddatecityagesexlast_visit_datecostmax_dwell_timemin_dwell_time
100002017-10-01北京2002017-10-01 07:00:0035102
100012017-10-01北京3012017-10-01 17:05:4522222
100022017-10-02上海2012017-10-02 12:59:1220055
100032017-10-02廣州3202017-10-02 11:20:00301111
100042017-10-01深圳3502017-10-01 10:00:1510033
100042017-10-03深圳3502017-10-03 11:22:0055196
100052017-10-03長沙2912017-10-03 18:11:02311

可以看到,用戶 10004 的已有數據和新導入的數據發生了聚合。同時新增了 10005 用戶的數據。

數據的聚合,在 Doris 中有如下三個階段發生:

  1. 每一批次數據導入的 ETL 階段。該階段會在每一批次導入的數據內部進行聚合。

  2. 底層 BE 進行數據 Compaction 的階段。該階段,BE 會對已導入的不同批次的數據進行進一步的聚合。

  3. 數據查詢階段。在數據查詢時,對于查詢涉及到的數據,會進行對應的聚合。

數據在不同時間,可能聚合的程度不一致。比如一批數據剛導入時,可能還未與之前已存在的數據進行聚合。但是對于用戶而言,用戶只能查詢到聚合后的數據。即不同的聚合程度對于用戶查詢而言是透明的。用戶需始終認為數據以最終的完成的聚合程度存在,而不應假設某些聚合還未發生。(可參閱聚合模型的局限性一節獲得更多詳情。)

Unique 唯一主鍵模型

在某些多維分析場景下,用戶更關注的是如何保證 Key 的唯一性,即如何獲得 Primary Key 唯一性約束。因此,我們引入了 Unique 的數據模型。該模型本質上是聚合模型的一個特例,也是一種簡化的表結構表示方式。我們舉例說明。

ColumnNameTypeIsKeyComment
user_idBIGINTYes用戶id
usernameVARCHAR(50)Yes用戶昵稱
cityVARCHAR(20)No用戶所在城市
ageSMALLINTNo用戶年齡
sexTINYINTNo用戶性別
phoneLARGEINTNo用戶電話
addressVARCHAR(500)No用戶住址
register_timeDATETIMENo用戶注冊時間

這是一個典型的用戶基礎信息表。這類數據沒有聚合需求,只需保證主鍵唯一性。(這里的主鍵為 user_id + username)。那么我們的建表語句如下:

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`)
... /* 省略 Partition 和 Distribution 信息 */
;

而這個表結構,完全同等于以下使用聚合模型描述的表結構:

ColumnNameTypeAggregationTypeComment
user_idBIGINT
用戶id
usernameVARCHAR(50)
用戶昵稱
cityVARCHAR(20)REPLACE用戶所在城市
ageSMALLINTREPLACE用戶年齡
sexTINYINTREPLACE用戶性別
phoneLARGEINTREPLACE用戶電話
addressVARCHAR(500)REPLACE用戶住址
register_timeDATETIMEREPLACE用戶注冊時間

及建表語句:

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`)
... /* 省略 Partition 和 Distribution 信息 */
;

即 Unique 模型完全可以用聚合模型中的 REPLACE 方式替代。其內部的實現方式和數據存儲方式也完全一樣。這里不再繼續舉例說明。

聚合模型的局限性

聚合模型(包括 Unique 模型),通過一種預計算的方式來減少查詢時需要實時計算的數據量,加速查詢。但是這種模型會有使用上的局限性。

在聚合模型中,模型對外展現的,是最終聚合后的數據。也就是說,任何還未聚合的數據(比如說兩個不同導入批次的數據),必須通過某種方式,以保證對外展示的一致性。我們舉例說明。

假設表結構如下:

ColumnNameTypeAggregationTypeComment
user_idLARGEINT
用戶id
dateDATE
數據灌入日期
costBIGINTSUM用戶總消費

假設存儲引擎中有如下兩個已經導入完成的批次的數據:

batch 1

user_iddatecost
100012017-11-2050
100022017-11-2139

batch 2

user_iddatecost
100012017-11-201
100012017-11-215
100032017-11-2222

可以看到,用戶 10001 分屬在兩個導入批次中的數據還沒有聚合。但是為了保證用戶只能查詢到如下最終聚合后的數據:

user_iddatecost
100012017-11-2051
100012017-11-215
100022017-11-2139
100032017-11-2222

我們在查詢引擎中加入了聚合算子,來保證數據對外的一致性。

另外,在聚合列(Value)上,執行與聚合類型不一致的聚合類查詢時,要注意語意。比如我們在如上示例中執行如下查詢:

SELECT MIN(cost) FROM table;

得到的結果是 5,而不是 1。

同時,這種一致性保證,在某些查詢中,會極大的降低查詢效率。

我們以最基本的 count(*) 查詢為例:

SELECT COUNT(*) FROM table;

在其他數據庫中,這類查詢都會很快的返回結果。因為在實現上,我們可以通過如 “導入時對行進行計數,保存 count 的統計信息”,或者在查詢時 “僅掃描某一列數據,獲得 count 值” 的方式,只需很小的開銷,即可獲得查詢結果。但是在 Doris 的聚合模型中,這種查詢的開銷非常大

我們以剛才的數據為例:

batch 1

user_iddatecost
100012017-11-2050
100022017-11-2139

batch 2

user_iddatecost
100012017-11-201
100012017-11-215
100032017-11-2222

因為最終的聚合結果為:

user_iddatecost
100012017-11-2051
100012017-11-215
100022017-11-2139
100032017-11-2222

所以,select count(*) from table; 的正確結果應該為 4。但如果我們只掃描 user_id 這一列,如果加上查詢時聚合,最終得到的結果是 3(10001, 10002, 10003)。而如果不加查詢時聚合,則得到的結果是 5(兩批次一共5行數據)。可見這兩個結果都是不對的。

為了得到正確的結果,我們必須同時讀取 user_iddate 這兩列的數據,再加上查詢時聚合,才能返回 4 這個正確的結果。也就是說,在 count() 查詢中,Doris 必須掃描所有的 AGGREGATE KEY 列(這里就是 user_iddate),并且聚合后,才能得到語意正確的結果。當聚合列非常多時,count() 查詢需要掃描大量的數據。

因此,當業務上有頻繁的 count(*) 查詢時,我們建議用戶通過增加一個值恒為 1 的,聚合類型為 SUM 的列來模擬 count(*)。如剛才的例子中的表結構,我們修改如下:

ColumnNameTypeAggregateTypeComment
user_idBIGINT
用戶id
dateDATE
數據灌入日期
costBIGINTSUM用戶總消費
countBIGINTSUM用于計算count

增加一個 count 列,并且導入數據中,該列值恒為 1。則 select count(*) from table; 的結果等價于 select sum(count) from table;。而后者的查詢效率將遠高于前者。不過這種方式也有使用限制,就是用戶需要自行保證,不會重復導入 AGGREGATE KEY 列都相同的行。否則,select sum(count) from table; 只能表述原始導入的行數,而不是 select count(*) from table; 的語義。

另一種方式,就是 將如上的 count 列的聚合類型改為 REPLACE,且依然值恒為 1。那么 select sum(count) from table;select count(*) from table; 的結果將是一致的。并且這種方式,沒有導入重復行的限制。

Duplicate 模型

Duplicate 模型沒有聚合模型的這個局限性。因為該模型不涉及聚合語意,在做 count(*) 查詢時,任意選擇一列查詢,即可得到語意正確的結果。

數據模型的選擇建議

因為數據模型在建表時就已經確定,且無法修改。所以,選擇一個合適的數據模型非常重要

  1. Aggregate 模型可以通過預聚合,極大地降低聚合查詢時所需掃描的數據量和查詢的計算量,非常適合有固定模式的報表類查詢場景。但是該模型對 count(*) 查詢很不友好。同時因為固定了 Value 列上的聚合方式,在進行其他類型的聚合查詢時,需要考慮語意正確性。

  2. Unique 模型針對需要唯一主鍵約束的場景,可以保證主鍵唯一性約束。但是無法利用 ROLLUP 等預聚合帶來的查詢優勢(因為本質是 REPLACE,沒有 SUM 這種聚合方式)。

  3. Duplicate 適合任意維度的 Ad-hoc 查詢。雖然同樣無法利用預聚合的特性,但是不受聚合模型的約束,可以發揮列存模型的優勢(只讀取相關列,而不需要讀取所有 Key 列)。

到此,關于“Apache Doris數據模型的介紹”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

南和县| 塔河县| 承德县| 巴彦淖尔市| 舞钢市| 延津县| 法库县| 安岳县| 华安县| 巴中市| 石柱| 临澧县| 通州区| 永城市| 两当县| 湖州市| 岳普湖县| 松潘县| 南京市| 永嘉县| 茂名市| 西安市| 榕江县| 布拖县| 崇阳县| 上蔡县| 屏南县| 交城县| 淳化县| 中江县| 克东县| 盘山县| 论坛| 涟源市| 巴里| 炎陵县| 梅河口市| 咸阳市| 绥化市| 康乐县| 高安市|