Starrocks 的 ShortCircuit短路径

背景

本文基于 Starrocks 3.3.5
本文主要来探索一下Starrocks在FE端怎么实现 短路径,从而加速点查查询速度。
在用户层级需要设置 enable_short_circuit 为true

分析

数据流:
直接到StatementPlanner.createQueryPlan方法:

...
OptExpression root = ShortCircuitPlanner.checkSupportShortCircuitRead(logicalPlan.getRoot(), session);
...
optimizedPlan = optimizer.optimize(session,root,mvTransformerContext,stmt,new PhysicalPropertySet(),new ColumnRefSet(logicalPlan.getOutputColumn()),columnRefFactory);

首先是通过ShortCircuitPlanner.checkSupportShortCircuitRead来判断该SQL是不是支持短路径查询:

 public static OptExpression checkSupportShortCircuitRead(OptExpression root, ConnectContext connectContext) {if (!connectContext.getSessionVariable().isEnableShortCircuit()) {root.setShortCircuit(false);return root;}boolean supportShortCircuit = root.getOp().accept(new LogicalPlanChecker(), root, null);if (supportShortCircuit && OperatorType.LOGICAL_LIMIT.equals(root.getOp().getOpType())) {root = root.getInputs().get(0);}root.setShortCircuit(supportShortCircuit);return root;}
  • 通过isEnableShortCircuit也就是enable_short_circuit(默认是false) 来判断是否支持短路径查询
  • 通过visitor LogicalPlanChecker来判断SQL本身是否支持短路径查询
    通过 LogicalPlanChecker 实现看到,目前只支持 Scan Project Filter Limit 操作:
     public static class LogicalPlanChecker extends BaseLogicalPlanChecker {...@Overridepublic Boolean visitLogicalFilter(OptExpression optExpression, Void context) {...return visitChild(optExpression, context);}@Overridepublic Boolean visitLogicalProject(OptExpression optExpression, Void context) {...return visitChild(optExpression, context);}@Overridepublic Boolean visitLogicalLimit(OptExpression optExpression, Void context) {...return visitChild(optExpression, context);}@Overridepublic Boolean visitLogicalTableScan(OptExpression optExpression, Void context) {return createLogicalPlanChecker(optExpression, allowFilter, allowLimit, allowProject,allowSort, predicate, orderByColumns, limit).visitLogicalTableScan(optExpression, context);}protected static boolean isPointScan(Table table,List<String> keyColumns,List<ScalarOperator> conjuncts,ShortCircuitContext shortCircuitContext) {Map<String, PartitionColumnFilter> filters = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);filters.putAll(ColumnFilterConverter.convertColumnFilter(conjuncts, table));if (keyColumns == null || keyColumns.isEmpty()) {return false;}long cardinality = 1;for (String keyColumn : keyColumns) {if (filters.containsKey(keyColumn)) {PartitionColumnFilter filter = filters.get(keyColumn);if (filter.getInPredicateLiterals() != null) {cardinality *= filter.getInPredicateLiterals().size();// TODO(limit operator place fe)if (cardinality > MAX_RETURN_ROWS ||(shortCircuitContext.getMaxReturnRows() != 0 && cardinality != 1)) {return false;}} else if (!filter.isPoint()) {return false;}} else {return false;}}return true;}}}
    
    • 直接看visitLogicalTableScan这个方法
      只有是存算一体的,也就是LogicalOlapScanOperator实例,才会有短路径查询,最终会走到ShortCircuitPlannerHybrid.LogicalPlanChecker.visitLogicalTableScan方法
      public Boolean visitLogicalTableScan(OptExpression optExpression, Void context) {LogicalScanOperator scanOp = optExpression.getOp().cast();Table table = scanOp.getTable();if (!(table instanceof OlapTable) || !(KeysType.PRIMARY_KEYS.equals(((OlapTable) table).getKeysType()))) {return false;}for (Column column : table.getFullSchema()) {if (IDictManager.getInstance().hasGlobalDict(table.getId(), column.getColumnId())) {return false;}}List<String> keyColumns = ((OlapTable) table).getKeyColumns().stream().map(Column::getName).collect(Collectors.toList());List<ScalarOperator> conjuncts = Utils.extractConjuncts(predicate);return isPointScan(table, keyColumns, conjuncts, shortCircuitContext);}
      
      • 首先必须满足 是主键模型
      • 再次是 必须满足SQL 查询的表和字段没有全局字典
      • 最后 判断是不是点查
        满足:1. 过滤条件要么是IN,要么是=
        2. 如果是IN的话,IN中的项不能超过2024个
        3. 必须包含所有的主键(可以额外包含其他的非主键)
  • 如果确定可以走短路径的话,则设置root.setShortCircuit(true),否则为false

再次进行计划级别的优化 optimizer.optimize:
这里会调用optimizeByCost方法,到调用 rewriteAndValidatePlan方法:

 private OptExpression rewriteAndValidatePlan(OptExpression tree,TaskContext rootTaskContext) {OptExpression result = logicalRuleRewrite(tree, rootTaskContext);OptExpressionValidator validator = new OptExpressionValidator();validator.validate(result);// skip memoif (result.getShortCircuit()) {result = new OlapScanImplementationRule().transform(result, null).get(0);result.setShortCircuit(true);}return result;}

ShortCircuit 短路径涉及到的有两方面:

  1. logicalRuleRewrite中 ruleRewriteForShortCircuit
        private Optional<OptExpression> ruleRewriteForShortCircuit(OptExpression tree, TaskContext rootTaskContext) {Boolean isShortCircuit = tree.getShortCircuit();if (isShortCircuit) {deriveLogicalProperty(tree);ruleRewriteIterative(tree, rootTaskContext, RuleSetType.SHORT_CIRCUIT_SET);ruleRewriteOnlyOnce(tree, rootTaskContext, new MergeProjectWithChildRule());OptExpression result = tree.getInputs().get(0);result.setShortCircuit(true);return Optional.of(result);}return Optional.empty();}
    

这里会专门针对于shortCircuit做一些规则优化:

new PruneTrueFilterRule(),
new PushDownPredicateProjectRule(),
PushDownPredicateScanRule.OLAP_SCAN,
new CastToEmptyRule(),
new PruneProjectColumnsRule(),
PruneScanColumnRule.OLAP_SCAN,
new PruneProjectEmptyRule(),
new MergeTwoProjectRule(),
new PruneProjectRule(),
new PartitionPruneRule(),
new DistributionPruneRule();
 new MergeProjectWithChildRule()

以上规则只是在project以及 常量优化,以及更好的过滤数据的层级进行了优化,免去了一般性的规则过滤. 正如primary_key_table所说,由于primary key模型使得谓词下推成为了可能。

  1. OlapScanImplementationRule().transform
    这个也是在该SQL能够进行短路径的情况下,才会走到的数据流
    这一步的作用主要是把逻辑的scan转换为物理的scan

经过了以上两步以后,就直接返回了,也不会进入到memo的CBO优化。
至此 FE端 短路径的 优化就结束了,接下来就是生成物理计划了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/79360.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Oracle非归档模式遇到文件损坏怎么办?

昨天夜里基地夜班的兄弟&#xff0c;打电话说有个报表库连不上了&#xff0c;赶紧起来连上VPN查看一下&#xff0c;看到实例宕机了&#xff0c;先赶紧startup起来。 1.查看报错信息 环境介绍&#xff1a;Redhat 6.9 Oracle 11.2.0.4 No Archive Mode 查看alert log 关键报…

关于一些平时操作系统或者软件的步骤转载

关于一些平时操作系统或者软件的步骤转载 关于python环境搭建 关于Ubuntu 1. 双系统之Ubuntu快速卸载 2. VMware安装Ubuntu虚拟机实现COpenCV代码在虚拟机下运行教程 3. ubuntu 下 opencv的安装以及配置&#xff08;亲测有效&#xff09; 4. Ubuntu将c编译成.so文件并测试 5…

hz2新建Keyword页面

新建一个single-keywords.php即可&#xff0c;需要筛选项再建taxonomy-knowledge-category.php 参考&#xff1a;https://www.tkwlkj.com/customize-wordpress-category-pages.html WordPress中使用了ACF创建了自定义产品分类products&#xff0c;现在想实现自定义产品分类下的…

VRRP协议-IP地址冗余配置

有两个服务器172.16.42.1和172.16.42.121&#xff0c;通过VRRP协议使两台设备共用一个虚拟地址172.16.42.100&#xff0c;当 172.16.42.1 可用时&#xff0c;它会作为主路由器使用虚拟 IP 地址&#xff1b;当它不可用时&#xff0c;172.16.42.121 会接管虚拟 IP 地址&#xff0…

21、DeepSeekMath论文笔记(GRPO)

DeepSeekMath论文笔记 0、研究背景与目标1、GRPO结构GRPO结构PPO知识点**1. PPO的网络模型结构****2. GAE&#xff08;广义优势估计&#xff09;原理****1. 优势函数的定义**2.GAE&#xff08;广义优势估计&#xff09; 2、关键技术与方法3、核心实验结果4、结论与未来方向关键…

卡尔曼滤波算法(C语言)

此处感谢华南虎和互联网的众多大佬的无偿分享。 入门常识 先简单了解以下概念&#xff1a;叠加性&#xff0c;齐次性。 用大白话讲&#xff0c;叠加性&#xff1a;多个输入对输出有影响。齐次性&#xff1a;输入放大多少倍&#xff0c;输出也跟着放大多少倍 卡尔曼滤波符合这…

SolidWork-2023 鼠標工程

地址 https://github.com/MartinxMax/SW2023-Project/tree/main/mouse 鼠標

vue 组件函数式调用实战:以身份验证弹窗为例

通常我们在 Vue 中使用组件&#xff0c;是像这样在模板中写标签&#xff1a; <MyComponent :prop"value" event"handleEvent" />而函数式调用&#xff0c;则是让我们像调用一个普通 JavaScript 函数一样来使用这个组件&#xff0c;例如&#xff1a;…

Vite Proxy配置详解:从入门到实战应用

Vite Proxy配置详解&#xff1a;从入门到实战应用 一、什么是Proxy代理&#xff1f; Proxy&#xff08;代理&#xff09;是开发中常用的解决跨域问题的方案。Vite内置了基于http-proxy的代理功能&#xff0c;可以轻松配置API请求转发。 二、基础配置 在vite.config.js中配置…

图像画质算法记录(前言)

一、背景介绍 本篇主要是对图像画质增强相关&#xff0c;进行简单整理和记录。 二、整体流程 整体效果主要受到两部分影响&#xff1a; 1、前端isp处理。 2、后端画质增强。 三、isp常规流程 可以参考&#xff1a;刘斯宁&#xff1a;Understanding ISP Pipeline 四、后端画质…

Qt 中信号与槽(signal-slot)机制支持 多种连接方式(ConnectionType)

Qt 中信号与槽&#xff08;signal-slot&#xff09;机制支持 多种连接方式&#xff08;ConnectionType&#xff09; Qt 中信号与槽&#xff08;signal-slot&#xff09;机制支持 多种连接方式&#xff08;ConnectionType&#xff09;&#xff0c;用于控制信号发出后如何调用槽…

卷积神经网络实战(4)代码详解

目录 一、导包 二、数据准备 1.数据集 2. 标准化转换(Normalize) 3.设置dataloader 三、定义模型 四、可视化计算图&#xff08;不重要&#xff09; 五、评估函数 六、Tensorboard 一、导包 import matplotlib as mpl import matplotlib.pyplot as plt %matplotlib i…

深入解析进程地址空间:从虚拟到物理的奇妙之旅

深入解析进程地址空间&#xff1a;从虚拟到物理的奇妙之旅 前言 各位小伙伴&#xff0c;还记得我们之前探讨的 fork 函数吗&#xff1f;当它返回两次时&#xff0c;父子进程中同名变量却拥有不同值的现象&#xff0c;曾让我们惊叹于进程独立性与写时拷贝的精妙设计。但你是否…

opencv处理图像(二)

接下来进入到程序线程设计部分 我们主线程负责图形渲染等操作&#xff0c;OpenGL的限制&#xff0c;opencv技术对传入图像加以处理&#xff0c;输出预期图像给主线程 QThread 我之前也是在想给opencv开一个专门的线程&#xff0c;但经过了解有几个弊端&#xff0c;第一资源浪…

学习threejs,使用Physijs物理引擎

&#x1f468;‍⚕️ 主页&#xff1a; gis分享者 &#x1f468;‍⚕️ 感谢各位大佬 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍⚕️ 收录于专栏&#xff1a;threejs gis工程师 文章目录 一、&#x1f340;前言1.1 ☘️Physijs 物理引擎1.1.1 ☘️…

ARCGIS PRO DSK 选择坐标系控件(CoordinateSystemsControl )的调用

在WPF窗体上使用 xml&#xff1a;加入空间命名引用 xmlns:mapping"clr-namespace:ArcGIS.Desktop.Mapping.Controls;assemblyArcGIS.Desktop.Mapping" 在控件区域加入&#xff1a; <mapping:CoordinateSystemsControl x:Name"CoordinateSystemsControl&q…

LangGraph(三)——添加记忆

目录 1. 创建MemorySaver检查指针2. 构建并编译Graph3. 与聊天机器人互动4. 问一个后续问题5. 检查State参考 1. 创建MemorySaver检查指针 创建MemorySaver检查指针&#xff1a; from langgraph.checkpoint.memory import MemorySavermemory MemorySaver()这是位于内存中的检…

深入理解Mysql

BufferPool和Changebuffer是如何加快读写速度的? BufferPool 在Mysql启动的时候 Mysql会申请连续的空间来存储BufferPool 每个页16kb 当控制块不足以存储信息的时候就会向后申请一个新的页 每个控制块都对应了一个缓存页 控制块占chunk的百分之5左右 LRU链表 Changebuffer …

Python核心编程深度解析:作用域、递归与匿名函数的工程实践

引言 Python作为现代编程语言的代表&#xff0c;其作用域管理、递归算法和匿名函数机制是构建高质量代码的核心要素。本文基于Python 3.11环境&#xff0c;结合工业级开发实践&#xff0c;深入探讨变量作用域的内在逻辑、递归算法的优化策略以及匿名函数的高效应用&#xff0c…

《用MATLAB玩转游戏开发》贪吃蛇的百变玩法:从命令行到AI对战

《用MATLAB玩转游戏开发&#xff1a;从零开始打造你的数字乐园》基础篇&#xff08;2D图形交互&#xff09;-&#x1f40d; 贪吃蛇的百变玩法&#xff1a;从命令行到AI对战 &#x1f3ae; 欢迎来到这篇MATLAB贪吃蛇编程全攻略&#xff01;本文将带你从零开始&#xff0c;一步步…