Doris 這類 MPP 架構的 OLAP 數據庫,一般都是經過提升併發,來處理大量數據的。本質上,Doris 的數據存儲在相似 SSTable(Sorted String Table)的數據結構中。該結構是一種有序的數據結構,能夠按照指定的列進行排序存儲。在這種數據結構上,以排序列做爲條件進行查找,會很是的高效。html
Count(*)
語法方面,原生的方式性能不是特別高,須要自行優化(http://doris.apache.org/docum...)在 Doris 中,數據以表(Table)的形式進行邏輯上的描述。一張表包括行(Row)和列(Column)。Row 即用戶的一行數據。Column 用於描述一行數據中不一樣的字段。sql
Column 能夠分爲兩大類:Key 和 Value。從業務角度看,Key 和 Value 能夠分別對應維度列和指標列。docker
Doris 的數據模型主要分爲3類:數據庫
在 Doris 經過 key 來來決定 value 的聚合粒度大小。apache
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 信息 */ ;
像帶有 REPLACE、SUM、MAX、MIN 這種標記的字段都是屬於 value,user_id
, date
, timestamp
, city
, age
, sex
則爲key。數據結構
這類數據沒有聚合需求,只需保證主鍵惟一性。架構
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 信息 */ ;
在某些多維分析場景下,數據既沒有主鍵,也沒有聚合需求。所以,咱們引入 Duplicate 數據模型來知足這類需求。併發
這種數據模型區別於 Aggregate 和 Uniq 模型。數據徹底按照導入文件中的數據進行存儲,不會有任何聚合。即便兩行數據徹底相同,也都會保留。 而在建表語句中指定的 DUPLICATE KEY,只是用來指明底層數據按照那些列進行排序。分佈式
在 DUPLICATE KEY 的選擇上,咱們建議適當的選擇前 2-4 列就能夠。高併發
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 信息 */ ;
由於數據模型在建表時就已經肯定,且沒法修改。因此,選擇一個合適的數據模型很是重要。
在 Aggregate、Uniq 和 Duplicate 三種數據模型中。底層的數據存儲,是按照各自建表語句中,AGGREGATE KEY、UNIQ KEY 和 DUPLICATE KEY 中指定的列進行排序存儲的。
而前綴索引,即在排序的基礎上,實現的一種根據給定前綴列,快速查詢數據的索引方式。
咱們將一行數據的前 36 個字節 做爲這行數據的前綴索引。當遇到 VARCHAR 類型時,前綴索引會直接截斷。咱們舉例說明:
ColumnName | Type |
---|---|
user_id | BIGINT |
age | INT |
message | VARCHAR(100) |
max_dwell_time | DATETIME |
min_dwell_time | DATETIME |
ColumnName | Type |
---|---|
user_name | VARCHAR(20) |
age | INT |
message | VARCHAR(100) |
max_dwell_time | DATETIME |
min_dwell_time | DATETIME |
當咱們的查詢條件,是前綴索引的前綴時,能夠極大的加快查詢速度。好比在第一個例子中,咱們執行以下查詢:
SELECT * FROM table WHERE user_id=1829239 and age=20;
該查詢的效率會遠高於以下查詢:
SELECT * FROM table WHERE age=20;
因此在建表時,正確的選擇列順序,可以極大地提升查詢效率。
ROLLUP 在多維分析中是「上卷」的意思,即將數據按某種指定的粒度進行進一步聚合。
在 Doris 中,咱們將用戶經過建表語句建立出來的表成爲 Base 表(Base Table)。Base 表中保存着按用戶建表語句指定的方式存儲的基礎數據。
在 Base 表之上,咱們能夠建立任意多個 ROLLUP 表。這些 ROLLUP 的數據是基於 Base 表產生的,而且在物理上是獨立存儲的。
ROLLUP 表的基本做用,在於在 Base 表的基礎上,得到更粗粒度的聚合數據。
Rollup 本質上能夠理解爲原始表(Base Table)的一個物化索引。創建 Rollup 時可只選取 Base Table 中的部分列做爲 Schema。Schema 中的字段順序也可與 Base Table 不一樣。
ROLLUP 建立完成以後的觸發是程序自動的,不須要任何其餘指定或者配置。
例如:建立了 user_id (key),cost(value)格式的 rollup 時,當執行下方語句時,就會觸發。
SELECT user_id, sum(cost) FROM table GROUP BY user_id;
Aggregate 和 Uniq 兩種數據存儲格式時,使用 rollup 會改變聚合數據的粒度,但對於 Duplicate 只是調整前綴索引。
由於建表時已經指定了列順序,因此一個表只有一種前綴索引。這對於使用其餘不能命中前綴索引的列做爲條件進行的查詢來講,效率上可能沒法知足需求。所以,咱們能夠經過建立 ROLLUP 來人爲的調整列順序。舉例說明。
Base 表結構以下:
ColumnName | Type |
---|---|
user_id | BIGINT |
age | INT |
message | VARCHAR(100) |
max_dwell_time | DATETIME |
min_dwell_time | DATETIME |
咱們能夠在此基礎上建立一個 ROLLUP 表:
ColumnName | Type |
---|---|
age | INT |
user_id | BIGINT |
message | VARCHAR(100) |
max_dwell_time | DATETIME |
min_dwell_time | DATETIME |
能夠看到,ROLLUP 和 Base 表的列徹底同樣,只是將 user_id 和 age 的順序調換了。那麼當咱們進行以下查詢時:
SELECT * FROM table where age=20 and massage LIKE "%error%";
會優先選擇 ROLLUP 表,由於 ROLLUP 的前綴索引匹配度更高。
建立 rollup 語法
ALTER TABLE table1 ADD ROLLUP rollup_city(citycode, pv); # 取消正在執行的做業 CANCEL ALTER TABLE ROLLUP FROM table1;
由於建表時已經指定了列順序,因此一個表只有一種前綴索引。這對於使用其餘不能命中前綴索引的列做爲條件進行的查詢來講,效率上可能沒法知足需求。所以,咱們能夠經過建立 ROLLUP 來人爲的調整列順序。
EXPLAIN your_sql;
命令得到查詢執行計劃,在執行計劃中,查看是否命中 ROLLUP。DESC tbl_name ALL;
語句顯示 Base 表和全部已建立完成的 ROLLUP。rollup 數量沒有限制,但數量越多會消耗比較多的內存。支持 SQL 方式變動 rollup 字段數量。
Doris 支持兩級分區存儲, 第一層爲 RANGE 分區(partition), 第二層爲 HASH 分桶(bucket)。
1.3.1. RANGE分區(partition)
RANGE分區用於將數據劃分紅不一樣區間, 邏輯上能夠理解爲將原始表劃分紅了多個子表。業務上,多數用戶會選擇採用按時間進行partition, 讓時間進行partition有如下好處: * 可區分冷熱數據 * 可用上Doris分級存儲(SSD + SATA)的功能 * 按分區刪除數據時,更加迅速
1.3.2. HASH分桶(bucket)
根據hash值將數據劃分紅不一樣的 bucket。 * 建議採用區分度大的列作分桶, 避免出現數據傾斜 * 爲方便數據恢復, 建議單個 bucket 的 size 不要太大, 保持在 10GB 之內, 因此建表或增長 partition 時請合理考慮 bucket 數目, 其中不一樣 partition 可指定不一樣的 buckets 數。
Doris對數據進行有序存儲, 在數據有序的基礎上爲其創建稀疏索引,索引粒度爲 block(1024行)。
稀疏索引選取 schema 中固定長度的前綴做爲索引內容, 目前 Doris 選取 36 個字節的前綴做爲索引。
系統默認實現 Join 的方式,是將小表進行條件過濾後,將其廣播到大表所在的各個節點上,造成一個內存 Hash 表,而後流式讀出大表的數據進行Hash Join。可是若是當小表過濾後的數據量沒法放入內存的話,此時 Join 將沒法完成,一般的報錯應該是首先形成內存超限。
若是遇到上述狀況,建議使用 Shuffle Join 的方式,也被稱做 Partitioned Join。即將小表和大表都按照 Join 的 key 進行 Hash,而後進行分佈式的 Join。這個對內存的消耗就會分攤到集羣的全部計算節點上。
支持,但數據模式一旦表建立就沒法變動。
不存在,但越多的 rollup 內存資源會消耗更多,同時,導入數據會比較慢。
支持,但要有順序要求。
Doris 表結構由 key 和 value 構成,key 爲維度,value 爲統計指標。適合作簡單的聚合計算和維度計算,使用比較低的硬件條件擁有比較高的性能。
Doris 官方還推出了 Docker 的 Dev 版本進行特性試用。https://hub.docker.com/r/apac...