1. 列式存储(序号或者行号??是怎么保证的??)
StarRocks中, 一张表的列可以分为维度列(也成为key列)和指标列(value列), 维度列用于分组和排序, 指标列可通过聚合函数SUM, COUNT, MIN, MAX, REPLACE, HLL_UNION, BITMAP_UNION等累加起来. 因此, StarRocks的表也可以认为是多维的key到多维指标的映射。
在StarRocks中, 表中数据按列存储, 物理上, 一列数据会经过分块编码压缩等操作, 然后持久化于非易失设备, 但在逻辑上, 一列数据可以看成由相同类型的元素构成的数组. 一行数据的所有列在各自的列数组中保持对齐, 即拥有相同的数组下标, 该下标称之为序号或者行号. 该序号是隐式, 不需要存储的, 表中的所有行按照维度列, 做多重排序, 排序后的位置就是该行的行号。
查询时, 如果指定了维度列的等值条件或者范围条件, 并且这些条件中维度列可构成表维度列的前缀, 则可以利用数据的有序性, 使用range-scan快速锁定目标行. 例如: 对于表table1: (event_day, siteid, citycode, username)➜(pv); 当查询条件为event_day > 2020-09-18 and siteid = 2, 则可以使用范围查找; 如果指定条件为citycode = 4 and username in ["Andy", "Boby", "Christian", "StarRocks"], 则无法使用范围查找。
2. 稀疏索引(不是很明白??)
- shortkey index表: 表中数据每1024行, 构成一个逻辑block. 每个逻辑block在shortkey index表中存储一项索引, 内容为表的维度列的前缀, 并且不超过36字节. shortkey index为稀疏索引, 用数据行的维度列的前缀查找索引表, 可以确定该行数据所在逻辑块的起始行号。
- Per-column data block: 表中每一列数据按64KB分块存储, 数据块作为一个单位单独编码压缩, 也作为IO单位, 整体写回设备或者读出。
- Per-column cardinal index: 表中的每列数据有各自的行号索引表, 列的数据块和行号索引项一一对应, 索引项由数据块的起始行号和数据块的位置和长度信息构成, 用数据行的行号查找行号索引表, 可以获取包含该行号的数据块所在位置, 读取目标数据块后, 可以进一步查找数据。
我的理解是shortkey index表是表的行对应的其起始维度的key。这些key也是存储在不同的行上,列式存储??但是维度列的前缀是什么意思??怎么对应行号的(Per-column cardinal index)???
3. 加速数据处理
- 预先聚合
- 分区分桶
- RollUp表索引
- 列级别的索引技术
4. 数据模型
StarRocks的排序键对比传统的主键具有:
- 数据表所有维度列构成排序键, 所以后文中提及的排序列, key列本质上都是维度列。
- 排序键可重复, 不必满足唯一性约束。
- 数据表的每一列, 以排序键的顺序, 聚簇存储。
- 排序键使用稀疏索引。
需要注意的点:
- 建表语句, 排序列的定义必须出现在指标列定义之前。
- 排序列在建表语句中的出现次序为数据行的多重排序的次序。
- 排序键的稀疏索引(Shortkey Index)会选择排序键的若干前缀列。
明细模型(Duplicate Key)
一般用明细模型来处理的场景有如下特点:
- 需要保留原始的数据(例如原始日志,原始操作记录等)来进行分析;
- 查询方式灵活, 不局限于预先定义的分析方式, 传统的预聚合方式难以命中;
- 数据更新不频繁。导入数据的来源一般为日志数据或者是时序数据, 以追加写为主要特点, 数据产生后就不会发生太多变化。
注意事项
- 充分利用排序列,在建表时将经常在查询中用于过滤的列放在表的前面,这样能够提升查询速度。
- 明细模型中, 可以指定部分的维度列为排序键; 而聚合模型和更新模型中, 排序键只能是全体维度列。
聚合模型(Aggregate Key)
在数据分析领域,有很多需要对数据进行统计和汇总操作的场景:
- 分析网站或APP访问流量,统计用户的访问总时长、访问总次数;
- 广告厂商为广告主提供的广告点击总量、展示总量、消费统计等;
- 分析电商的全年的交易数据, 获得某指定季度或者月份的, 各人口分类(geographic)的爆款商品。
原理:
StarRocks会将指标列按照相同维度列进行聚合。当多条数据具有相同的维度时,StarRocks会把指标进行聚合。从而能够减少查询时所需要的处理的数据量,进而提升查询的效率。
更新模型(Unique Key)
主键模型(Primary Key)
由于存储引擎会为主键建立索引,而在导入数据时会把主键索引加载在内存中,所以主键模型对内存的要求比较高,还不适合主键特别多的场景。目前primary主键存储在内存中,为防止滥用造成内存占满,限制主键字段长度全部加起来编码后不能超过127字节。目前比较适合的两个场景是:
- 数据有冷热特征
- 大宽表(数百到数千列)
原有的表模型整体上采用了读时合并(Merge-On-Read)的策略,写入时处理简单高效,但是读取(查询)时需要在线合并多版本。由于Merge算子的存在使得谓词无法下推和索引无法使用,严重影响了查询性能。而主键模型通过主键约束,保证同一个主键下仅存在一条记录,这样就完全避免了Merge操作。
排序键
StarRocks中为加速查询,在内部组织并存储数据时,会把表中数据按照指定的列进行排序,这部分用于排序的列(可以是一个或多个列),可以称之为Sort Key。明细模型中Sort Key就是指定的用于排序的列(即 DUPLICATE KEY 指定的列),聚合模型中Sort Key列就是用于聚合的列(即 AGGREGATE KEY 指定的列),更新模型中Sort Key就是指定的满足唯一性约束的列(即 UNIQUE KEY 指定的列)。
如何选择排序列
物化视图
Bitmap索引
适用场景
- 非前缀过滤
StarRocks对于建表中的前置列可以通过shortkey索引快速过滤,但是对于非前置列, 无法利用shortkey索引快速过滤,如果需要对非前置列进行快速过滤,就可以对这些列建立Bitmap索引。 - 多列过滤Filter
由于Bitmap可以快速的进行bitwise运算。所以在多列过滤的场景中,也可以考虑对每列分别建立Bitmap索引。
Bloomfilter 索引
Bloom Filter(布隆过滤器)是用于判断某个元素是否在一个集合中的数据结构,优点是空间效率和时间效率都比较高,缺点是有一定的误判率。
适用场景
- 首先BloomFilter也适用于非前缀过滤。
- 查询会根据该列高频过滤,而且查询条件大多是in和=。
- 不同于Bitmap, BloomFilter适用于高基数列。