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


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

    1.基本概念

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

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

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

    2.Aggregate 和 Uniq 模型中的 ROLLUP

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

    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;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    2.1 获得每个用户的总消费

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

    desc example_site_visit2 all;
    
    • 1

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

    alter table example_site_visit2 add rollup rollup_cost_userid(user_id,cost);
    
    • 1

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

    desc example_site_visit2 all;
    
    • 1

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

    explain SELECT user_id, sum(cost) FROM example_site_visit2 GROUP BY user_id;
    
    • 1

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

    SHOW ALTER TABLE ROLLUP;
    
    • 1

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

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

    alter table example_site_visit2 add rollup rollup_city_age_cost_maxd_mind(city,age,cost,max_dwell_time,min_dwell_time);
    
    • 1

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

    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;
    
    • 1
    • 2
    • 3

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

    SHOW ALTER TABLE ROLLUP;
    
    • 1

    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)。

    ColumnNameType
    user_idBIGINT
    ageINT
    messageVARCHAR(100)
    max_dwell_timeDATETIME
    min_dwell_timeDATETIME

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

    ColumnNameType
    user_nameVARCHAR(20)
    ageINT
    messageVARCHAR(100)
    max_dwell_timeDATETIME
    min_dwell_timeDATETIME

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

    SELECT * FROM table WHERE user_id=1829239 and age=20;
    
    • 1

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

    SELECT * FROM table WHERE age=20;
    
    • 1

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

    3.2 ROLLUP 调整前缀索引

    因为建表时已经指定了列顺序,所以一个表只有一种前缀索引。这对于使用其他不能命中前缀索引的列作为条件进行的查询来说,效率上可能无法满足需求。因此,我们可以通过创建 ROLLUP 来人为的调整列顺序。举例说明。

    Base 表结构如下:

    ColumnNameType
    user_idBIGINT
    ageINT
    messageVARCHAR(100)
    max_dwell_timeDATETIME
    min_dwell_timeDATETIME

    我们可以在此基础上创建一个 ROLLUP 表:

    ColumnNameType
    ageINT
    user_idBIGINT
    messageVARCHAR(100)
    max_dwell_timeDATETIME
    min_dwell_timeDATETIME

    可以看到,ROLLUP 和 Base 表的列完全一样,只是将 user_idage 的顺序调换了。那么当我们进行如下查询时:

    SELECT * FROM table where age=20 and message LIKE "%error%";
    
    • 1

    会优先选择 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。

  • 相关阅读:
    深入实战:构建现代化的Web前端应用
    由浅到深带你详谈Java实现数组扩容的三种方式【建议收藏】
    【云原生之k8s】k8s资源限制以及探针检查
    全面升级!Apache HugeGraph 1.2.0版本发布
    Ubuntu22.04系统安装Unreal Engine 5.1.0
    图解系列--密钥,随机数,应用技术
    快速构建基于Paddle Serving部署的Paddle Detection目标检测Docker镜像
    前端(十七)——gitee上开源一个移动端礼盒商城项目(前端+后台)
    目标检测—Yolo系列(YOLOv1/2/v3/4/5/x/6/7/8)
    数据结构 线性表 ——— 顺序表
  • 原文地址:https://blog.csdn.net/be_racle/article/details/134084221