当进行tb1 join tb2
时,tb2的数据非常小,将tb2数据经过计算得到一个过滤条件,发送到tb1所在的节点,利用索引的功能,直接对tb1的数据进行过滤。来减少扫描的数据量,避免不必要的I/O 和网络传输,从而加速查询
Runtime Filter在查询规划时生成,在HashJoinNode中构建,在ScanNode中应用
T1表的数据很大,比如100万条。等T2将扫描的数据记录交给HashJoinNode后,HashJoinNode根据T2的数据计算出一个过滤条件,然后将这个过滤条件发给T1的ScanNode,T1在储存引擎用索引对数据进行过滤,只需扫描6000条数据即可,T1再将数据返回给HashJoinNode
Runtime Filter是在运行时动态生成的过滤条件,即在查询运行时解析join on clause确定过滤表达式,并将表达式广播给正在读取左表的ScanNode
主要应用于join左表为大标,右表为小表。如果左表的数据量太小,或者右表的数据量太大,则Runtime Filter可能不会取得预期效果
指定RuntimeFilter类型。根据两表的数据分布情况,选择一个或多个。可以为
数字(1, 2, 4, 8)或者相对应的字符串(IN, BLOOM_FILTER, MIN_MAX, IN_OR_BLOOM_FILTER),默认8(IN_OR_BLOOM_FILTER),使用多个时用逗号分隔,注意需要加引号,或者将任意多个类型的数字相加
mysql> set runtime_filter_type="BLOOM_FILTER,IN,MIN_MAX";
Query OK, 0 rows affected (0.01 sec)
mysql>
查看执行计划
mysql> explain select * from click a join user_live b on a.user_id = b.user_id;
+------------------------------------------------------------------------------------------------------------------------------+
| Explain String |
+------------------------------------------------------------------------------------------------------------------------------+
......省略部分......
| 2:VHASH JOIN |
| | join op: INNER JOIN(BROADCAST)[Tables are not in the same group] |
| | equal join conjunct: `a`.`user_id` = `b`.`user_id` |
| | runtime filters: RF000[in] <- `b`.`user_id`, RF001[bloom] <- `b`.`user_id`, RF002[min_max] <- `b`.`user_id` |
| | cardinality=0 |
| | vec output tuple id: 2 | |
| |----3:VEXCHANGE |
| | |
| 0:VOlapScanNode |
| TABLE: click(null), PREAGGREGATION: OFF. Reason: No AggregateInfo |
| runtime filters: RF000[in] -> `a`.`user_id`, RF001[bloom] -> `a`.`user_id`, RF002[min_max] -> `a`.`user_id` |
| partitions=0/2, tablets=0/0, tabletList= |
| cardinality=0, avgRowSize=56.0, numNodes=1
......省略部分......
+------------------------------------------------------------------------------------------------------------------------------+
33 rows in set (0.01 sec)
mysql>
生成了ID为RF000的IN predicate,其中b
.user_id
的key values仅在运行时可知,在VOlapScanNode使用了该IN predicate,用于在读取a
.user_id
时过滤不必要的数据
通过profile查看效果:
开启profile
mysql> show variables like '%enable_profile%';
+----------------+-------+
| Variable_name | Value |
+----------------+-------+
| enable_profile | false |
+----------------+-------+
1 row in set (0.01 sec)
mysql>
mysql> set enable_profile=true;
Query OK, 0 rows affected (0.01 sec)
mysql>
再进行select的join查询,打开FE的Web界面,查看QueryProfile
在点击Query ID查看详细的信息。其中RuntimeFilter部分的信息如下:
RuntimeFilter:in:
- RealRuntimeFilterType: in
- AWaitTimeCost: 0ns
- EffectTimeCost: 19.709ms
RuntimeFilter:bloomfilter:
- AWaitTimeCost: 0ns
- EffectTimeCost: 19.699ms
RuntimeFilter:minmax:
- AWaitTimeCost: 0ns
- EffectTimeCost: 19.697ms
可以看到只要in这个Runtime Filter下推,其等待耗时为0、OLAP_SCAN_NODE 从prepare到接收到Runtime Filter的总时长为19.709ms
查看RuntimeFilter上面OlapScanner的RowsVectorPredFiltered和VectorPredEvalTime,可以查看Runtime Filter下推后的过滤效果和耗时
大多数情况下,只需要调整runtime_filter_type选项,其他选项保持默认即可
runtime_filter_type每个类型含义如下:
其他查询选项通常仅在某些特定场景下调整。通常只在性能测试后,针对资源密集型、运行耗时足够长且频率足够高的查询进行优化
下面摘自Doris官网,能明白个大概