【大数据 - Doris 实践】数据表的基本使用(五):ROLLUP

数据表的基本使用(五):ROLLUP

  • 1.基本概念
  • [2.Aggregate 和 Uniq 模型中的 ROLLUP](#2.Aggregate 和 Uniq 模型中的 ROLLUP)
    • [2.1 获得每个用户的总消费](#2.1 获得每个用户的总消费)
    • [2.2 获得不同城市,不同年龄段用户的总消费、最长和最短页面驻留时间](#2.2 获得不同城市,不同年龄段用户的总消费、最长和最短页面驻留时间)
  • [3.Duplicate 模型中的 ROLLUP](#3.Duplicate 模型中的 ROLLUP)
    • [3.1 前缀索引](#3.1 前缀索引)
    • [3.2 ROLLUP 调整前缀索引](#3.2 ROLLUP 调整前缀索引)
  • [4.ROLLUP 的几点说明](#4.ROLLUP 的几点说明)

ROLLUP 在多维分析中是 "上卷" 的意思,即将数据按某种指定的粒度进行进一步聚合。

1.基本概念

在 Doris 中,我们将用户通过建表语句创建出来的表称为 Base 表(Base Table)。Base 表中保存着按用户建表语句指定的方式存储的基础数据。

在 Base 表之上,我们可以创建任意多个 ROLLUP 表。这些 ROLLUP 的数据是基于 Base 表产生的,并且在物理上是独立存储的。

ROLLUP 表的基本作用,在于在 Base 表的基础上,获得更粗粒度的聚合数据。

2.Aggregate 和 Uniq 模型中的 ROLLUP

因为 Uniq 只是 Aggregate 模型的一个特例,所以这里我们不加以区别。

sql 复制代码
CREATE TABLE IF NOT EXISTS test_db.example_site_visit2
(
	`user_id` LARGEINT NOT NULL COMMENT "用户 id",
	`date` DATE NOT NULL COMMENT "数据灌入日期时间",
	`timestamp` DATETIME 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`)
DISTRIBUTED BY HASH(`user_id`) BUCKETS 10;

2.1 获得每个用户的总消费

(1)查看表的结构信息。

sql 复制代码
desc example_site_visit2 all;

(2)比如需要查看某个用户的总消费,那么可以建立一个只有 user_idcost 的 ROLLUP。

sql 复制代码
alter table example_site_visit2 add rollup rollup_cost_userid(user_id,cost);

(3)查看表的结构信息。

sql 复制代码
desc example_site_visit2 all;

(4)然后可以通过 explain 查看执行计划,是否使用到了 ROLLUP。Doris 会自动命中这个 ROLLUP 表,从而只需扫描极少的数据量,即可完成这次聚合查询。

sql 复制代码
explain SELECT user_id, sum(cost) FROM example_site_visit2 GROUP BY user_id;

(5)通过命令查看完成状态

sql 复制代码
SHOW ALTER TABLE ROLLUP;

2.2 获得不同城市,不同年龄段用户的总消费、最长和最短页面驻留时间

(1)我们在 Base 表基础之上,再创建一个 ROLLUP。

sql 复制代码
alter table example_site_visit2 add rollup rollup_city_age_cost_maxd_mind(city,age,cost,max_dwell_time,min_dwell_time);

(2)当我们进行如下这些查询时,Doris 执行这些 SQL 时会自动命中这个 ROLLUP 表。

sql 复制代码
explain SELECT city, age, sum(cost), max(max_dwell_time), min(min_dwell_time) FROM example_site_visit2 GROUP BY city, age;
explain SELECT city, sum(cost), max(max_dwell_time), min(min_dwell_time) FROM example_site_visit2 GROUP BY city;
explain SELECT city, age, sum(cost), min(min_dwell_time) FROM example_site_visit2 GROUP BY city, age;

(3)通过命令查看完成状态。

sql 复制代码
SHOW ALTER TABLE ROLLUP;

3.Duplicate 模型中的 ROLLUP

因为 Duplicate 模型没有聚合的语意。所以该模型中的 ROLLUP,已经失去了 "上卷" 这一层含义,而仅仅是作为调整列顺序,以命中前缀索引的作用。下面详细介绍前缀索引,以及如何使用 ROLLUP 改变前缀索引,以获得更好的查询效率。

3.1 前缀索引

不同于传统的数据库设计,Doris 不支持在任意列上创建索引。Doris 这类 MPP 架构的 OLAP 数据库,通常都是通过提高并发,来处理大量数据的。

本质上,Doris 的数据存储在类似 SSTableSorted String Table)的数据结构中。该结构是一种有序的数据结构,可以按照指定的列进行排序存储。在这种数据结构上,以排序列作为条件进行查找,会非常的高效。

在 Aggregate、Uniq 和 Duplicate 三种数据模型中。底层的数据存储,是按照各自建表语句中,AGGREGATE KEY、UNIQ KEY 和 DUPLICATE KEY 中指定的列进行排序存储的。而前缀索引,即在排序的基础上,实现的一种根据给定前缀列,快速查询数据的索引方式。

我们将一行数据的前 36 36 36 个字节作为这行数据的前缀索引。当遇到 VARCHAR 类型时,前缀索引会直接截断。举例说明:

(1)以下表结构的前缀索引为 user_id( 8 8 8 Bytes)+ age( 4 4 4 Bytes)+ message(前 20 20 20 Bytes)。

ColumnName Type
user_id BIGINT
age INT
message VARCHAR(100)
max_dwell_time DATETIME
min_dwell_time DATETIME

(2)而以下表结构的前缀索引为 user_name( 20 20 20 Bytes)。即使没有达到 36 36 36 个字节,因为遇到 VARCHAR,所以直接截断,不再往后继续。

ColumnName Type
user_name VARCHAR(20)
age INT
message VARCHAR(100)
max_dwell_time DATETIME
min_dwell_time DATETIME

当我们的查询条件,是前缀索引的前缀时,可以极大的加快查询速度。比如在第一个例子中,我们执行如下查询:

sql 复制代码
SELECT * FROM table WHERE user_id=1829239 and age=20;

该查询的效率会远高于如下查询:

sql 复制代码
SELECT * FROM table WHERE age=20;

所以在建表时,正确的选择列顺序,能够极大地提高查询效率。

3.2 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_idage 的顺序调换了。那么当我们进行如下查询时:

sql 复制代码
SELECT * FROM table where age=20 and message LIKE "%error%";

会优先选择 ROLLUP 表,因为 ROLLUP 的前缀索引匹配度更高。

4.ROLLUP 的几点说明

  • ROLLUP 最根本的作用是提高某些查询的查询效率(无论是通过聚合来减少数据量,还是修改列顺序以匹配前缀索引)。因此 ROLLUP 的含义已经超出了 "上卷" 的范围。这也是为什么在源代码中,将其命名为 Materialized Index物化索引)的原因。

  • ROLLUP 是附属于 Base 表的,可以看做是 Base 表的一种辅助数据结构。用户可以在 Base 表的基础上,创建或删除 ROLLUP,但是不能在查询中显式的指定查询某 ROLLUP。是否命中 ROLLUP 完全由 Doris 系统自动决定

  • ROLLUP 的数据是独立物理存储的。因此,创建的 ROLLUP 越多,占用的磁盘空间也就越大。同时对导入速度也会有影响(导入的 ETL 阶段会自动产生所有 ROLLUP 的数据),但是不会降低查询效率(只会更好)。

  • ROLLUP 的数据更新与 Base 表是完全同步的。用户无需关心这个问题。

  • ROLLUP 中列的聚合方式,与 Base 表完全相同。在创建 ROLLUP 无需指定,也不能修改。

  • 查询能否命中 ROLLUP 的一个必要条件(非充分条件)是,查询所涉及的所有列(包括 select list 和 where 中的查询条件列等)都存在于该 ROLLUP 的列中。否则,查询只能命中 Base 表。

  • 某些类型的查询(如 count(*))在任何条件下,都无法命中 ROLLUP。

  • 可以通过 EXPLAIN your_sql 命令获得查询执行计划,在执行计划中,查看是否命中 ROLLUP。

  • 可以通过 DESC tbl_name ALL 语句显示 Base 表和所有已创建完成的 ROLLUP。

相关推荐
师太,答应老衲吧2 小时前
SQL实战训练之,力扣:2020. 无流量的帐户数(递归)
数据库·sql·leetcode
Channing Lewis3 小时前
salesforce case可以新建一个roll up 字段,统计出这个case下的email数量吗
数据库·salesforce
毕业设计制作和分享4 小时前
ssm《数据库系统原理》课程平台的设计与实现+vue
前端·数据库·vue.js·oracle·mybatis
ketil274 小时前
Redis - String 字符串
数据库·redis·缓存
Hsu_kk5 小时前
MySQL 批量删除海量数据的几种方法
数据库·mysql
编程学无止境5 小时前
第02章 MySQL环境搭建
数据库·mysql
昨天今天明天好多天5 小时前
【数据仓库】
大数据
knight-n5 小时前
MYSQL库的操作
数据库·mysql
油头少年_w5 小时前
大数据导论及分布式存储HadoopHDFS入门
大数据·hadoop·hdfs
包饭厅咸鱼6 小时前
QML----复制指定下标的ListModel数据
开发语言·数据库