国产数据库-内核特性-StarRocks低基数全局字典
StarRocks2.0引入了低基数全局字典,可以通过全局字典将字符串的相关操作转换成整型相关操作,大大提升查询性能。
1、低基数字典
对于利用整型替代字符串进行处理,通常使用字典编码进行优化。StarRocks也是利用这样的技术。以过滤为例:一个city列,里面有:BJ,SH,GZ,SZ四个字符串,需要从里面过滤city=’BJ’的值,普通操作就需要city整个字段与‘BJ’比较进行匹配;使用字典编码,将上面的4个字符串依次编码为:1,2,3,4。那么过滤时仅需city=1进行比较。将字符串比较转换成整数比较。大多数情况下,整数之间的比较性能会高于字符串的性能。
2、局部字典
在存储层进行字典编码。存储时并不存储原有字符串数据,而是将字符串编码后的值。但是额外会有个元数据,即编码值与原有字符串之间的映射关系,即字典。写入和读取时能够节省很多IO开销。
3、全局字典
分布式执行引擎中,一个查询可能会涉及多个机器多个任务之间数据交换。因此执行过程中需要保证字典全局性。字典数据始终贯穿 SQL 执行的整个生命周期,如果不是全局字典,那么加速只能在局部进行。例如如果两个执行节点的字典编码不一致,那么在网络传输过程中需要同时把字典传给对端机器,或者是需要提前把字典码转为字符串再通过网络发送。如果能保证一个字典的全局性,在网络传输中就可以直接使用字典码而不再需要传输字典。
StarRocks中有全局字典,各个节点之间共享同一个字典,那么就不需要发送后再进行解码并转换字典码了。
4、如何构建全局字典
1)建表时定义:
这样,用户不友好,并且不易维护。除非用户数据事先就定义好,数据值比较少,就那么几个。
2)导入时构建
导入数据时,通过中心节点维护全局字典。每次遇到新的的字符都要通过中心节点创建一个新的字典码。但是这么做的主要问题是中心节点很容易会成为瓶颈。另外中心节点因为需要同时处理维护并发控制。
因为维护和构建字典对于很多系统来说都是一个比较困难的事情,因此很多系统,只是在局部使用了局部字典来进行加速,并不支持字典的全局加速
3)查询时构建
发起一个查询,就能拿到全量数据,然后对其进行编码。代价比较高。
4)StarRocks的构建方式
StarRocks 的基本存储单元为 Segment,每个 Segment 的存储结构上图所示。
StarRocks 的存储结构天然为低基数字符串做了字典编码。对于 Segment 上的低基数字符串列会有以下特点:Footer 上会存储有这个 Column 特有的字典信息,包括字典码跟原始字符串之间的映射关系;Data page 上存储的不是原始字符串,而是整数类型的字典码(整型)。当处理低基数 String column 的时候,直接使用编码后的字典码,而不是直接处理原始的 String 值。当需要原始的 String 值时,使用字典码就可以很方便地在这个列的字典信息里面拿到原始 String 值。这么做带来的明显好处是:减少了磁盘IO。可以提前做一些过滤操作,提升处理速度。
根据统计信息筛选出低基数的列,并对低基数列进行字典编码。并不是对所有列进行编码。
5、全局字典的使用
如果使用了全局字典优化,我们就不需要 SCAN NODE 节点就进行 Decoded,而是可以将原先的局部字典码(int),直接映射到全局字典中的字典码(int),并在之后的计算处理过程中,均使用全局字典码进行处理。当遇到某些特殊的算子,或者是需要具体的依赖字符串内部信息的时候,再按着全局字典的信息,Decoded 出原始的 String 值,这样可以充分利用到全局字典的加速。
比如select count(*) from lineitem group by l_shipmode;不需要原始字符串值,那么整个执行过程仅使用字典码即可,而下面的语句select count(*), l_shipmode from lineitem group by l_shipmode;输出时还需要原始字符串,那么就需要在最后将字典码转换成字符串输出。
优化效果,号称能够提升3倍。
6、参考
https://www.bilibili.com/video/BV1ra411N7g8/?spm_id_from=333.337.search-card.all.click&vd_source=10ce859f3f7b1da2094a1283c19fe9b9