1.求 每个城市的 每个用户的 每天的总销售额
select user_id,city,date, sum(sum_cost) as sum_cost from t group by user_id,city,date
-- user_id date city sum_cost 10000 2017/10/2 北京 195 10000 2017/10/1 上海 100 10000 2017/10/2 上海 30 10000 2017/10/3 上海 55 10000 2017/10/4 上海 65 10001 2017/10/1 上海 30 10001 2017/10/2 上海 10 10001 2017/10/2 天津 18 10001 2017/10/1 天津 46 10002 2017/10/1 天津 55 10002 2017/10/3 北京 55 10002 2017/10/2 天津 20 10002 2017/10/2 北京 35
2.求每个用户、每个城市的总消费额
select user_id,city, sum(sum_cost) as sum_cost from t group by user_id,city
user_id city sum_cost 10000 北京 195 10000 上海 100 10001 上海 40 10001 天津 64 10002 天津 75 10002 北京 90
3.求每个用户的总消费额
select user_id, sum(sum_cost) as sum_cost from t group by user_id
user_id sum_cost 10000 295 10001 104 10002 165
3.5.1基本概念
通过建表语句创建出来的表称为 Base 表(Base Table,基表)
在 Base 表之上,我们可以创建任意多个 ROLLUP 表。这些 ROLLUP 的数据是基于 Base 表产生的,并且在物理上是 独立存储的。
Rollup表的好处:
-
和基表共用一个表名,doris会根据具体的查询逻辑选择合适的数据源(合适的表)来计算结果
-
对于基表中数据的增删改,rollup表会自动更新同步
3.5.2 Aggregate 模型中的 ROLLUP
示例1:查看某个用户的总消费
添加一个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;
再次查看该表得详细信息后发现,多了一个IndexName为rollup_cost_userid(这是我们自己取得roll
Up 名字)
Doris 会自动命中这个 ROLLUP 表,从而只需扫描极少的数据量,即可完成这次聚合查询。
explain SELECT user_id, sum(cost) FROM ex_user GROUP BY user_id;
示例 2:获得不同城市,不同年龄段用户的总消费、最长和最短页面驻留时间
alter table ex_user add rollup rollup_city(city,age,cost,max_dwell_time,min_dwell_time); -- 当创建好了立即去查看得时候就会发现,他还没有开始 SHOW ALTER TABLE ROLLUP; 然后过会再去查询得时候,他就完成了,看他的状态即可
explain SELECT city, age, sum(cost), max(max_dwell_time), min(min_dwell_time) FROM ex_user GROUP BY city, age; explain SELECT city, sum(cost), max(max_dwell_time), min(min_dwell_time) FROM ex_user GROUP BY city; explain SELECT city, age, sum(cost), min(min_dwell_time) FROM ex_user GROUP BY city, age;
很显然得发现,维度是city,或者age,或者他们组合得时候,都是可以命中这个rollup得,相对来说效率会高很多
3.5.3 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');
很显然,里面的数据是这样的
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表没有什么太多的意义
试想一下:
如果不沿用base表中所有的key,只针对上面的user_id进行rollup,那么他的age值取20还是19呢?好像也就不确定了,毕竟底层的aggregationType 用的是replace,到底谁替换谁就不确定了
3.5.4 Duplicate 模型中的 ROLLUP
因为 Duplicate 模型没有聚合的语意。所以该模型中的 ROLLUP,已经失去了“上卷” 这一层含义。而仅仅是作为调整列顺序,以命中前缀索引的作用。下面详细介绍前缀索引,以及如何使用 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 | +------------+---------------+------------+---------------+------+-------+---------+-------+---------+
示例:看如下sql会命中哪一张表
explain select * from log_detail where type = 1; explain select * from log_detail where type = 1 and error_code = 404; explain select * from log_detail where op_id = 101 ; explain select * from log_detail where op_id = 101 and error_code = 404; explain select * from log_detail where timestamp = '2017-10-01 08:00:05' ; explain select * from log_detail where timestamp = '2017-10-01 08:00:05' and type = 1;
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