目前我们只做了一个 pure dictionary compression,支持的算子也比较少,比如 predication 支持等值比较或者 in 等相似的比较可以在紧缩域上直接执行,这曾经可以覆盖我们很多的场景,像 group by 操作也可以在紧缩域上做。
说到 Global Dictionary,其实也并不是完全的 Global ,每个节点有本人的 Dictionary,但是在一个集群外部,各个节点之前的字典能够是不一样的。为什么没有做全局在集群外部做一个字典?
第一,全局字典会把 coordinate 协议搞得特别复杂,我以前做数据库的时分有个项目,采用了集群级别 Global Dictionary,碰到了比较多的应战。字典紧缩只支持了 MergeTree 相关的存储引擎。紧缩的行为发生次要有三种操作,像数据的插入或者数据的后台合并,都会触发 compression,还有很多数据的批量 roll in 或 roll out,也会做一些字典的异步构建。
刚才也提到,我们的次要出发点就是想在执行层去做非解压的计算,次要是做 Select query,每一个 Select 来的时分,我们都会在分析阶段做一些合法性的校验,评价其在紧缩域上直接执行能否可行,假如满足标准,就会改写语法树。假如紧缩的 column 会出如今输入的列表中,会显式地加一个 Decompress Stream 这样可选的算子,然后后续执行就不太需求改动,而是可以直接支持。当 equality 的比较以及 group by 操作直接在紧缩上执行,最后全体的收益大概提高 20% 到 30%。
刚才提到,我们的字典不是一个集群程度的,那大家能够会有所疑问,比如对分布式表的 query 怎样在紧缩域上做评价?我们稍微做了一些限制,很多时分运用紧缩场景的是用户行为分析系统,它是按用户 ID 去做 shard,然后节点之间基本做到没有交互。我们也引入了一个执行形式,稍微在它的现有计算上改了一下,我们叫做完美分布加智能合并的形式。在这个形式下,分布式表的 query 也是可以在字典上做评价。收益也还可以,满足当时设计时分的要求。
[attach]275167[/attach]
图 7 紧缩域执行
特定场景内存 OOM
有时分做一个系统,内存运用的成绩也会比较严重。尤其当做数据量大的系统时,常常发生内存受限的成绩,或者说 OOM 最后被系统杀掉。ClickHouse 由于有很多数据的加速,比如 Index & mark 文件,信息会在实例启动的时分加载,整个加载过程非常慢,有时分一个集群起来能够得要半个小时。
Array 类型处理的需求次要来自于 AB 实验的需求。当前我们的系统也会做一些实时 AB 目的的输入,实验 ID 在我们系统中以数组的方式存储。头条外部的 AB 实验也比较多,对于一个单条记录,它能够命中的实验数会有几百上千个。有时分我们需求查询命中实验的用户行为是什么样的,也就是要做一些 Array hasAny 语义的评价。
做大数据,能够最有效的优化方式就是怎样样做到底层数据的剪枝,数据少是提高数据处理速度的终极法宝。我们提出了如今的剪枝方法,一个是 Part level,一个是 MRK range level。那有没有一种针对于 Array column 的剪枝方式?我们做了下面两个尝试:
首先做了一个双尺度的 Bloom Filter,记录 Array 外面 Key 的运动状况,完成了 Part level 和细粒度的 MRK range level,做完后在一些小的产品上效果还挺好的,但最后真正在大产品上,像抖音、头条全量,我们发现 Fill factor 太高,实践上没太大协助。之后我们开发了一个 BitMap 索引,基本的想法是把 Array 的表示转化成 Value 和 Bit 的结合。在执行层改写,把 has 的评价直接转换成 get BitMap。