# Rollup ROLLUP 在多維分析中是“上捲”的意思,即將數據按某種指定的粒度進行進一步聚合。 通過建表語句創建出來的表稱為 Base 表(Base Table,基表) 在 Base 表之上,我們可以創建任意多個 ROLLUP 表。這些 ROLLUP 的數據是基於 Base 表產生的,並且在 ...
Rollup
ROLLUP 在多維分析中是“上捲”的意思,即將數據按某種指定的粒度進行進一步聚合。
通過建表語句創建出來的表稱為 Base 表(Base Table,基表)
在 Base 表之上,我們可以創建任意多個 ROLLUP 表。這些 ROLLUP 的數據是基於 Base 表產生的,並且在物理上是獨立存儲的。
Rollup表的好處:
- 和基表共用一個表名,doris會根據具體的查詢邏輯選擇合適的數據源(合適的表)來計算結果
- 對於基表中數據的增刪改,rollup表會自動更新同步
Aggregate 模型中的 ROLLUP
添加一個roll up
alter table aggregate表名 add rollup "rollup表的表名" (user_id,city,date,cost);
alter table ex_user add rollup rollup_ucd_cost(user_id,city,date,cost);
alter table ex_user add rollup rollup_u_cost(user_id,cost);
alter table ex_user add rollup rollup_cd_cost(city,date,cost);
alter table ex_user drop rollup rollup_u_cost;
alter table ex_user drop rollup rollup_cd_cost;
--如果是replace聚合類型得value,需要指定所有得key
-- alter table ex_user add rollup rollup_cd_visit(city,date,last_visit_date);
-- ERROR 1105 (HY000): errCode = 2, detailMessage = Rollup should contains
-- all keys if there is a REPLACE value
--添加完成之後可以show一下,看看底層的rollup有沒有執行完成
SHOW ALTER TABLE ROLLUP;
在查詢時, Doris 會自動命中這個 ROLLUP 表,從而只需掃描極少的數據量,即可完成這次聚合查詢。
explain SELECT user_id, sum(cost) FROM ex_user GROUP BY user_id;
獲取不同城市,不同年齡段用戶的總消費、最長和最短頁面駐留時間
alter table ex_user add rollup rollup_city(city,age,cost,max_dwell_time,min_dwell_time);
-- 當創建好了立即去查看得時候就會發現,他還沒有開始
SHOW ALTER TABLE ROLLUP;
然後過會再去查詢得時候,他就完成了,看他的狀態即可
Unique 模型中的 ROLLUP
-- unique模型示例表
drop table if exists test.user;
CREATE TABLE IF NOT EXISTS test.user
(
`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`, `username`)
DISTRIBUTED BY HASH(`user_id`) BUCKETS 1;
--插入語句
insert into test.user values\
(10000,'zss','北京',18,0,12345678910,'北京朝陽區 ','2017-10-01 07:00:00'),\
(10000,'zss','北京',18,0,12345678910,'北京朝陽區 ','2017-10-01 08:00:00'),\
(10001,'lss','北京',20,0,12345678910,'北京海澱區','2017-11-15 06:10:20');
-- 在unique模型中做rollup表,rollup的key必須延用base表中所有的key,不同的是value可以隨意指定
-- 所以說,unique模型中建立rollup表沒有什麼太多的意義
alter table user add rollup rollup_username_id(username,user_id,age);
Duplicate 模型中的 ROLLUP
因為 Duplicate 模型沒有聚合的語意。所以該模型中的 ROLLUP,已經失去了“上捲” 這一層含義。而僅僅是作為調整列順序,以命中首碼索引的作用。下麵詳細介紹首碼索引,以及如何使用 ROLLUP 改變首碼索引,以獲得更好的查詢效率。
ROLLUP 調整首碼索引(新增一套首碼索引)
因為建表時已經指定了列順序,所以一個表只有一種首碼索引。這對於使用其他不能命中首碼索引的列作為條件進行的查詢來說,效率上可能無法滿足需求。因此,我們可以通過創建 ROLLUP 來人為的調整列順序。
-- 針對log_detail這張基表添加兩個rollup表
-- 按照type 和error_code 進行建首碼索引
alter table log_detail add rollup rollup_tec(type,error_code,timestamp,error_msg,op_id,op_time);
alter table log_detail drop rolluprollup_tec
-- 按照op_id和error_code 進行建首碼索引
alter table log_detail add rollup rollup_oec(op_id,error_code,timestamp,type,error_msg,op_time);
-- 查看基表和rollup表
desc log_detail all;
ROLLUP使用說明
- ROLLUP 是附屬於 Base 表的,用戶可以在 Base 表的基礎上,創建或刪除 ROLLUP,但是不能在查詢中顯式的指定查詢某 ROLLUP。是否命中 ROLLUP 完全由 Doris 系統自動決定
- ROLLUP 的數據是獨立物理存儲的。因此,創建的 ROLLUP 越多,占用的磁碟空間也就越大。同時對導入速度也會有影響,但是不會降低查詢效率(只會更好)。
- ROLLUP 的數據更新與 Base 表是完全同步的。用戶無需關心這個問題。
- 在聚合模型中,ROLLUP 中列的聚合類型,與 Base 表完全相同。在創建 ROLLUP 無需指定,也不能修改。
- 可以通過 EXPLAIN your_sql; 命令獲得查詢執行計劃,在執行計劃中,查看是否命中 ROLLUP。
- 可以通過 DESC tbl_name ALL; 語句顯示 Base 表和所有已創建完成的 ROLLUP
物化視圖
就是查詢結果預先存儲起來的特殊的表。物化視圖的出現主要是為了滿足用戶,既能對原始明細數據的任意維度分析,也能快速的對固定維度進行分析查詢
優勢
- 可以復用預計算的結果來提高查詢效率 ==> 空間換時間
- 自動實時的維護物化視圖表中的結果數據,無需額外人工成本(自動維護會有計算資源的開銷)
- 查詢時,會自動選擇最優物化視圖
物化視圖 VS Rollup
• 明細模型表下,rollup和物化視圖的差別:
物化視圖:都可以實現預聚合,新增一套首碼索引
rollup:對於明細模型,新增一套首碼索引
• 聚合模型下,功能一致
創建物化視圖
CREATE MATERIALIZED VIEW [MV name] as
[query] -- sql邏輯
--[MV name]:物化視圖的名稱
--[query]:查詢條件,基於base表創建物化視圖的邏輯
-- 物化視圖創建成功後,用戶的查詢不需要發生任何改變,也就是還是查詢的 base 表。Doris 會根據當前查詢的語句去自動選擇一個最優的物化視圖,從物化視圖中讀取數據並計算。
-- 用戶可以通過 EXPLAIN 命令來檢查當前查詢是否使用了物化視圖。
create table sales_records(
record_id int,
seller_id int,
store_id int,
sale_date date,
sale_amt bigint)
duplicate key (record_id,seller_id,store_id,sale_date)
distributed by hash(record_id) buckets 2
properties("replication_num" = "1");
-- 插入數據
insert into sales_records values \
(1,1,1,'2022-02-02',100),\
(2,2,1,'2022-02-02',200),\
(3,3,2,'2022-02-02',300),\
(4,3,2,'2022-02-02',200),\
(5,2,1,'2022-02-02',100),\
(6,4,2,'2022-02-02',200),\
(7,7,3,'2022-02-02',300),\
(8,2,1,'2022-02-02',400),\
(9,9,4,'2022-02-02',100);
-- 創建一個物化視圖
select store_id, sum(sale_amt)
from sales_records
group by store_id;
CREATE MATERIALIZED VIEW store_id_sale_amonut as
select store_id, sum(sale_amt)
from sales_records
group by store_id;
CREATE MATERIALIZED VIEW store_amt as
select store_id, sum(sale_amt) as sum_amount
from sales_records
group by store_id;
--針對上述場景做一個物化視圖
create materialized view store_amt as
select store_id, sum(sale_amt) as sum_amount
from sales_records
group by store_id;
-- 檢查物化視圖是否構建完成(物化視圖的創建是個非同步的過程)
show alter table materialized view from 庫名 order by CreateTime desc limit 1;
show alter table materialized view from test order by CreateTime desc limit 1;
-- 查看 Base 表的所有物化視圖
desc sales_records all;
--查詢並查看是否命中剛纔我們建的物化視圖
EXPLAIN SELECT store_id, sum(sale_amt) FROM sales_records GROUP BY store_id;
-- 刪除物化視圖語法
-- 語法:
DROP MATERIALIZED VIEW 物化視圖名 on base_table_name;
--示例:
drop materialized view store_amt on sales_records;
練習
計算廣告的 pv、uv
pv:page view,頁面瀏覽量或點擊量
uv:unique view,通過互聯網訪問、瀏覽這個網頁的自然人
-- 創建表
drop table if exists ad_view_record;
create table ad_view_record(
dt date,
ad_page varchar(10),
channel varchar(10),
refer_page varchar(10),
user_id int
)
distributed by hash(dt)
properties("replication_num" = "1");
select
dt,ad_page,channel,
count(ad_page) as pv,
count(distinct user_id ) as uv
from ad_view_record
group by dt,ad_page,channel
-- 插入數據
insert into ad_view_record values \
('2020-02-02','a','app','/home',1),\
('2020-02-02','a','web','/home',1),\
('2020-02-02','a','app','/addbag',2),\
('2020-02-02','b','app','/home',1),\
('2020-02-02','b','web','/home',1),\
('2020-02-02','b','app','/addbag',2),\
('2020-02-02','b','app','/home',3),\
('2020-02-02','b','web','/home',3),\
('2020-02-02','c','app','/order',1),\
('2020-02-02','c','app','/home',1),\
('2020-02-03','c','web','/home',1),\
('2020-02-03','c','app','/order',4),\
('2020-02-03','c','app','/home',5),\
('2020-02-03','c','web','/home',6),\
('2020-02-03','d','app','/addbag',2),\
('2020-02-03','d','app','/home',2),\
('2020-02-03','d','web','/home',3),\
('2020-02-03','d','app','/addbag',4),\
('2020-02-03','d','app','/home',5),\
('2020-02-03','d','web','/addbag',6),\
('2020-02-03','d','app','/home',5),\
('2020-02-03','d','web','/home',4);
-- 創建物化視圖
-- 在doris的物化視圖中,一個欄位不能用兩次,並且聚合函數後面必須跟欄位名稱
-- count(distinct) 不能使用。需要用bitmap_union來代替
create materialized view tpc_pv_uv as
select
dt,ad_page,channel,
count(refer_page) as pv,
bitmap_union(to_bitmap(user_id)) as uv_bitmap
from ad_view_record
group by dt,ad_page,channel;
-- 在 Doris 中,count(distinct) 聚合的結果和 bitmap_union_count 聚合的結果是完全一致的。而 bitmap_union_count 等於 bitmap_union 的結果求 count,所以如果查詢中涉及到count(distinct) 則通過創建帶 bitmap_union 聚合的物化視圖方可加快查詢。因為本身 user_id 是一個 INT 類型,所以在 Doris 中需要先將欄位通過函數 to_bitmap 轉換為 bitmap 類型然後才可以進行 bitmap_union 聚合。