Doris基础知识篇(9):Runtime_Filter
概念
Runtime Filter
Runtime Filter 是在 Doris 0.15 版本中正式加入的新功能。旨在为某些 Join 查询在运行时动态生成过滤条件,来减少扫描的数据量,避免不必要的 I/O 和网络传输,从而加速查询
Runtime Filter 在查询规划时生成,在 HashJoinNode 中构建,在 ScanNode 中应用。
原理
先扫描数据量小的那个表,根据这个表的出一个限制条件(边界值、in等),使用限制条件直接限制另一张表的原始扫描数据量。
和谓词下推、分区裁剪不同, Runtime Filter 是在运行时动态生成的过滤条件,即在查询运行时解析 join on clause 确定过滤表达式,并将表达式广播给正在读取左表的ScanNode,从而减少扫描的数据量,进而减少 probe hash table 的次数,避免不必要的 I/O 和网络传输。
Runtime Filter 主要用于优化针对大表的 join,如果左表的数据量太小,或者右表的数据量太大,则 Runtime Filter 可能不会取得预期效果。
BloomFilter和IN
概念
在Doris中,runtime_filter_type='bloom_filter'和runtime_filter_type='in'是针对常规列扫描而设计的两种不同的运行时过滤器类型。
- Bloom Filter是一种基于哈希的概率性数据结构,可以高效地进行元素是否存在的查询,并且会将误差控制在可接受的范围内。在Doris中,如果在扫描某个列时设置了runtime_filter_type为'bloom_filter',则使用布隆过滤器来缩小扫描的范围,以提高查询性能。
- 然而,runtime_filter_type='in'则会检查扫描列中的值是否匹配给定的固定值集合。这种方法的优点是,它可以避免Bloom Filte可能会出现的误报问题(即错误地将不存在的元素标记为存在)。因此,这两种运行时过滤器都有其适用场景,根据具体情况选用相应的过滤器类型可以显著提升性能和减少资源消耗。
过滤性能
在子查询中,使用runtime_filter_type='bloom_filter'和runtime_filter_type='in'过滤器会对过滤的数据量级产生不同的影响。
- 当使用Bloom Filter时,它可以高效地确定一些显然不包含目标元素的块(Chunk),将这些块进行跳过,从而明显减少需要扫描的块数和时间开销。但是,如果该块上实际存在目标元素,则仍然需要进行查询操作,因此可能会比较慢。
- 而当使用'in'运行时过滤器时,它可以在最开始的时候就将过滤条件与值集合进行比较,并从原始块中删除不匹配的行,从而明显减少需要扫描的数据量级和时间消耗。但是,由于'in'过滤器需要完全扫描原始块,因此可能会增加资源消耗。总的来说,在数据量很大且筛选结果可能较少的情况下,推荐使用Bloom Filter进行优化,而在数据量较小且需要严格匹配条件的情况下,推荐使用'in'过滤器。
使用
指定类型 set **runtime_filter_type**="**BLOOM_FILTER**,**IN**,**MIN_MAX**"
查看执行计划 EXPLAIN SELECT t1 FROM test JOIN test2 where test.t1 = test2.t2;
过滤器
包括 BLOOM_FILTER、 IN、 MIN_MAX(也可以通过数字设置) ,默认会使用 IN,部分情况下同时使用 Bloom Filter、 MinMax Filter、 IN predicate 时性能更高,每个类型含义如下:
BloomFilter索引
BloomFilter是由Bloom在1970年提出的一种多哈希函数映射的快速查找算法。通常应用在一些需要快速判断某个元素是否属于集合,但是并不严格要求100%正确的场合,BloomFilter有以下特点:
- 空间效率高的概率型数据结构,用来检查一个元素是否在一个集合中。
- 对于一个元素检测是否存在的调用,BloomFilter会告诉调用者两个结果之一:可能存在或者一定不存在。
- 缺点是存在误判,告诉你可能存在,不一定真实存在。
布隆过滤器实际上是由一个超长的二进制位数组和一系列的哈希函数组成。二进制位数组初始全部为0,当给定一个待查询的元素时,这个元素会被一系列哈希函数计算映射出一系列的值,所有的值在位数组的偏移量处置为1。
下图所示出一个 m=18, k=3 (m是该Bit数组的大小,k是Hash函数的个数)的Bloom Filter示例。集合中的 x、y、z 三个元素通过 3 个不同的哈希函数散列到位数组中。当查询元素w时,通过Hash函数计算之后因为有一个比特为0,因此w不在该集合中。
那么怎么判断某个元素是否在集合中呢?同样是这个元素经过哈希函数计算后得到所有的偏移位置,若这些位置全都为1,则判断这个元素在这个集合中,若有一个不为1,则判断这个元素不在这个集合中。就是这么简单!
Doris的BloomFilter索引可以通过建表的时候指定,或者通过表的ALTER操作来完成。Bloom Filter本质上是一种位图结构,用于快速的判断一个给定的值是否在一个集合中。这种判断会产生小概率的误判。即如果返回false,则一定不在这个集合内。而如果范围true,则有可能在这个集合内。
BloomFilter索引也是以Block为粒度创建的。每个Block中,指定列的值作为一个集合生成一个BloomFilter索引条目,用于在查询是快速过滤不满足条件的数据。
创建
Doris BloomFilter索引的创建是通过在建表语句的PROPERTIES里加上**"bloom_filter_columns"="k1,k2,k3"**
**,**这个属性,k1,k2,k3是你要创建的BloomFilter索引的Key列名称,例如下面我们对表里的saler_id,category_id创建了BloomFilter索引。
1 | CREATE TABLE IF NOT EXISTS sale_detail_bloom ( |
其他操作:https://doris.apache.org/zh-CN/docs/data-table/index/bloomfilter
使用场景:
- 首先BloomFilter适用于非前缀过滤。
- 查询会根据该列高频过滤,而且查询条件大多是 in 和 = 过滤。
- 不同于Bitmap, BloomFilter适用于高基数列。比如UserID。因为如果创建在低基数的列上,比如 “性别” 列,则每个Block几乎都会包含所有取值,导致BloomFilter索引失去意义。
注意事项:
- 不支持对Tinyint、Float、Double 类型的列建Bloom Filter索引。
- Bloom Filter索引只对 in 和 = 过滤查询有加速效果。
- 如果要查看某个查询是否命中了Bloom Filter索引,可以通过查询的Profile信息查看。
MinMax Filter
IN predicate