数据模型、ROLLUP及前缀索引

数据模型、ROLLUP及前缀索引

基本概念

  • 一张表包括行(Row)和列(Column).Row即用户的一行数据.Column用于描述一行数据中不同的字段.
  • Column可以分为两大类:Key和Value.从业务角度看,Key和Value可以分为对应维度列和指标列.
  • Doris的数据模型主要分为三类:
    • Aggregate
    • Uniq
    • Duplicate

Aggregate模型

当导入数据时,对于Key列相同的行会聚合成一行,而Value列会按照设置的AggregationType进行聚合.AggregationType目前有以下四种聚合方式:

  1. SUM:求和
  2. REPLACE:替代
  3. MAX:保留最大值
  4. MIN:保留最小值

数据的聚合,在Doris中有如下三阶段发生:

  1. 每一批次数据导入的ETL阶段,该阶段会在每一个批次导入的数据内部进行聚合.
  2. 底层BE进行数据Compaction的阶段.该阶段,BE会对已导入的不同批次的数据进行进一步的聚合.
  3. 数据查询阶段.在数据查询时,对于查询涉及到的数据,会进行对应的聚合.

Uniq模型

Uniq模型完全可以用聚合模型中的REPLACE方式替换,其内部实现方式和数据存储方式也完全一样.

Duplicate模型

Duplicate模型区别于Aggregate和Uniq模型.数据完全按照导入文件中的数据进行存储,不会有任何聚合.即使两行数据完全相同,也都会保留.而在建表语句中指定DUPLICATE KEY,只是用来指明底层数据按照那些列进行排序.

RULLUP

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

基本概念

  • 在Doris中,将用户通过建表语句创建出来的表成为Base表(Base Table).Base表中保存着按用户建表语句指定的方式存储的基础数据.
  • 在Base表纸上,我们可以创建任意多个ROLLUP表.这些ROLLUP的数据是基于Base表产生的,并且在物理上是独立存储的.
  • ROLLUP表的基本作用,在于在Base表的基础上,获得更粗粒度的聚合数据.

前缀索引与ROLLUP

前缀索引

  • 不同于传统的数据库设计,Doris不支持在任意列上创建索引.Doris这类MPP架构的OLAP数据库,通常是通过提高并发,来处理大量数据的.
  • 本质上,Doris的数据存储在类似SSTable(Sorted String Table)的数据结构中.该结构是一种有序的数据结构,可以按照指定的列进行排序存储.在这种数据结构上,以排序列作为条件进行查找,会非常的高效.
  • 在Aggregate、Uniq和Duplicate三种数据模型中.底层的数据存储,是按照各自建表语句中,AGGREGATE KEY、UNIQ KEY和DUPLICATE KEY中指定的列进行排序存储的.
  • 而前缀索引,即在排序的基础上,实现一种根据给定前缀列,快速查询数据的索引方式.
  • 我们将一行的前36个字节做为这行数据的前缀索引,当遇到VARCHAR类型时,前缀索引会直接截断.

ROLLUP调整前缀索引

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

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。

聚合模型的局限性

  • 在聚合模型中,模型对外展现的,是最终聚合后的数据.也就是说,任何还未聚合的数据(比如两个不同批次的数据)必须通过某种方式,以保证对外展示的一致性.
  • 当业务上有频繁的count(*)时查询时,建议用户通过增加一个值恒为1的,聚合类型为SUM的列来模拟count(*)
  • 增加一个count列,并且导入数据中,该列值恒为1,则select count(*) from table的结果等价于select sum(count) from table.而后者的查询效率将远高于前者.不过这种方式也有使用限制,需要用户保证不会重复导入AGGREGATE KEY列都相同的行,否则,select sum(count) from table只能表述导入的行数,而不是select count(*) from table的语义.
  • 另一种方式,就是将如上count列的聚合类型改为REPLACE,且依然值恒为1,那么select sum(count) from tableselect count(*) from table结果将是一致的,没有导入重复行的限制.

数据模型的选择建议

因为数据模型在建表时就已经确定,且无法修改。所以,选择一个合适的数据模型非常重要。

  1. Aggregate 模型可以通过预聚合,极大地降低聚合查询时所需扫描的数据量和查询的计算量,非常适合有固定模式的报表类查询场景。但是该模型对 count(*) 查询很不友好。同时因为固定了 Value 列上的聚合方式,在进行其他类型的聚合查询时,需要考虑语意正确性。
  2. Uniq 模型针对需要唯一主键约束的场景,可以保证主键唯一性约束。但是无法利用 ROLLUP 等预聚合带来的查询优势(因为本质是 REPLACE,没有 SUM 这种聚合方式)。
  3. Duplicate 适合任意维度的 Ad-hoc 查询。虽然同样无法利用预聚合的特性,但是不受聚合模型的约束,可以发挥列存模型的优势(只读取相关列,而不需要读取所有 Key 列)。

你可能感兴趣的:(Doris学习笔记,数据库,数据仓库)