通过建表语句创建出来的表称为 Base 表(Base Table,基表)
在 Base 表之上,我们可以创建任意多个 ROLLUP 表。这些 ROLLUP 的数据是基于 Base 表产生的,并且在物理上是独立存储的。
Rollup表的好处:
查看之前建的表格:
mysql> desc ex_user all;
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;
再次查看该表得详细信息后发现,多了一个IndexName为rollup_cost_userid(这是我们自己取得rollUp 名字)
Doris 会自动命中这个 ROLLUP 表,从而只需扫描极少的数据量,即可完成这次聚合查询。
explain SELECT user_id, sum(cost) FROM ex_user GROUP BY user_id;
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');
里面的数据是这样的
mysql> select * from user;
+---------+----------+--------+------+------+-------------+------------------+---------------------+
| user_id | username | city | age | sex | phone | address | register_time |
+---------+----------+--------+------+------+-------------+------------------+---------------------+
| 10000 | lss | 北京 | 20 | 0 | 12345678910 | 北京海淀区 | 2017-11-15 06:10:20 |
| 10000 | zss | 北京 | 19 | 0 | 12345678910 | 北京朝阳区 | 2017-10-01 07:00:00 |
+---------+----------+--------+------+------+-------------+------------------+---------------------+
在unique模型中做rollup表,rollup的key必须延用base表中所有的key,不同的是value可以随意指定
alter table user add rollup rollup_username_id(username,user_id,age);
因此,unique模型中建立rollup表没有什么太多的意义。
ROLLUP 调整前缀索引(新增一套前缀索引)
因为建表时已经指定了列顺序,所以一个表只有一种前缀索引。这对于使用其他不能命中前缀索引的列作为条件进行的查询来说,效率上可能无法满足需求。因此,我们可以通过创建 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 message LIKE "%error%";
会优先选择 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表
mysql> desc log_detail all;
+------------+---------------+------------+---------------+------+-------+---------+-------+---------+
| IndexName | IndexKeysType | Field | Type | Null | Key | Default | Extra | Visible |
+------------+---------------+------------+---------------+------+-------+---------+-------+---------+
| log_detail | DUP_KEYS | timestamp | DATETIME | No | true | NULL | | true |
| | | type | INT | No | true | NULL | | true |
| | | error_code | INT | Yes | false | NULL | NONE | true |
| | | error_msg | VARCHAR(1024) | Yes | false | NULL | NONE | true |
| | | op_id | BIGINT | Yes | false | NULL | NONE | true |
| | | op_time | DATETIME | Yes | false | NULL | NONE | true |
| | | | | | | | | |
| rollup_oec | DUP_KEYS | op_id | BIGINT | Yes | true | NULL | | true |
| | | error_code | INT | Yes | true | NULL | | true |
| | | timestamp | DATETIME | No | true | NULL | | true |
| | | type | INT | No | false | NULL | NONE | true |
| | | error_msg | VARCHAR(1024) | Yes | false | NULL | NONE | true |
| | | op_time | DATETIME | Yes | false | NULL | NONE | true |
| | | | | | | | | |
| rollup_tec | DUP_KEYS | type | INT | No | true | NULL | | true |
| | | error_code | INT | Yes | true | NULL | | true |
| | | timestamp | DATETIME | No | true | NULL | | true |
| | | error_msg | VARCHAR(1024) | Yes | false | NULL | NONE | true |
| | | op_id | BIGINT | Yes | false | NULL | NONE | true |
| | | op_time | DATETIME | Yes | false | NULL | NONE | true |
+------------+---------------+------------+---------------+------+-------+---------+-------+---------+
ROLLUP使用说明
物化视图就是查询结果预先存储起来的特殊的表。物化视图的出现主要是为了满足用户,既能对原始明细数据的任意维度分析,也能快速的对固定维度进行分析查询
优势
物化视图 与 Rollup
创建物化视图
语法:
CREATE MATERIALIZED VIEW [MV name] as
[query] -- sql逻辑
--[MV name]:雾化视图的名称
--[query]:查询条件,基于base表创建雾化视图的逻辑
取消正在创建的物化视图
CANCEL ALTER MATERIALIZED VIEW FROM db_name.table_name
案例:计算广告的 pv、uv
用户有一张点击广告的明细数据表
需求:针对用户点击计广告明细数据的表,算每天,每个页面,每个渠道的 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);
创建物化视图
-- 怎么去计算pv,uv
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;
-- 1.物化视图中,不能够使用两个相同的字段
-- 2.在增量聚合里面,不能够使用count(distinct) ==> bitmap_union
-- 3.count(字段)
create materialized view dpc_pv_uv as
select
dt,ad_page,channel,
-- refer_page 没有null的情况
count(refer_page) as pv,
-- doris的物化视图中,不支持count(distint) ==> bitmap_union
-- count(distinct user_id) as uv
bitmap_union(to_bitmap(user_id)) uv_bitmap
from ad_view_record
group by dt,ad_page,channel;
//1. count(必须加字段名) 不能写count(1)
//2.同一个字段在物化视图的sql逻辑中不能出现两次
//3. count(distinct) 不能使用。需要用bitmap_union来代替
create materialized view tpc_pv_uv as
select
dt,ad_page,channel,
count(refer_page) as pv,
-- refer_page 不能为null
-- count(user_id) as pv
-- count(1) as pv,
bitmap_union(to_bitmap(user_id)) as uv_bitmap
--count(distinct user_id) as uv
from ad_view_record
group by dt,ad_page,channel;
--结论:在doris的物化视图中,一个字段不能用两次,并且聚合函数后面必须跟字段名称
在 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 聚合。
查询自动匹配
explain
select
dt,ad_page,channel,
count(refer_page) as pv,
count(distinct user_id) as uv
from ad_view_record
group by dt,ad_page,channel;
会自动转换成。
explain
select
dt,ad_page,channel,
count(1) as pv,
bitmap_union_count(to_bitmap(user_id)) as uv
from ad_view_record
group by dt,ad_page,channel;
这个sql用的是哪张表呢?
explain
select
dt,ad_page,
count(refer_page) as pv,
count(distinct user_id) as uv
from ad_view_record
group by dt,ad_page;
TABLE: ad_view_record_1(tpc_pv_uv), PREAGGREGATION: ON
-- 很显然命中的是tpc_pv_uv 这个物化视图
还可以根据日期和页面的维度再去创建一张物化视图
create materialized view tp_pv_uv as
select
dt,ad_page,
count(refer_page) as pv,
bitmap_union(to_bitmap(user_id)) as uv
from ad_view_record
group by dt,ad_page;
再去执行上面的sql,显然命中的就是tp_pv_uv这个物化视图
explain
select
dt,ad_page,
count(refer_page) as pv,
count(distinct user_id) as uv
from ad_view_record
group by dt,ad_page;
-- TABLE: ad_view_record_1(tp_pv_uv), PREAGGREGATION: ON
explain
select
dt,
count(refer_page) as pv,
count(distinct user_id) as uv
from ad_view_record
group by dt;
总结: