Presto 从提交SQL到获取结果 源码详解(2)

逻辑执行计划:

//进入逻辑执行计划阶段
doAnalyzeQuery().new LogicalPlanner().plan(analysis);//createAnalyzePlan
createAnalyzePlan(analysis, (Analyze) statement);//返回RelationPlan,(返回root根节点,逻辑树上包含输出字段、meta与字段映射关系、索引等)
return createOutputPlan(planStatementWithoutOutput(analysis, statement), analysis);/*
逻辑执行计划是基于Visitor模型生成的,逻辑计划为受访者,优化器为访问者
逻辑执行计划的节点都是PlanNode的实现类:最核心的accept()方法,代表这个当前node接收访问,就是调用Visitor的visitPlan()方法LogicalPlanner 遍历各种优化器对应的 optimize()方法。对PlanTree 进行优化,并对生成的Plan 进行验证。
优化过程中,优化器会在 Plan中插入 Exchange 结点。之后planFragmenter会根据这些Exchange结点将 Plan切分成 SubPlan。
*/if (stage.ordinal() >= Stage.OPTIMIZED.ordinal()) {for (PlanOptimizer optimizer : planOptimizers) {root = optimizer.optimize(root, session, symbolAllocator.getTypes(), symbolAllocator, idAllocator, warningCollector);requireNonNull(root, format("%s returned a null plan", optimizer.getClass().getName()));}
}//optimizer.optimize方法中,以rewritewith形式,重写现有逻辑树
SimplePlanRewriter.rewriteWith

优化器介绍:

常规优化器:

        需要实现optimize()方法。且需要自定义和实现整个Visitor的角色,即重载vistor*()的相关方法,例如visitAggregation,visitTopN,visitOutput等(PlanVisitor中定义了各种visit*()方法)

大致流程:

PlanOptimizer
    .optimize 
        .visitPlan
            context.defaultRewrite
                .rewrite
                .replace
            是否继续替换条件判断
                否:生成PlanNode返回

当 PlanNode 接受 Rewriter时,会进行
1. PlanNode 类型匹配:Rewriter 中的每个 visit* 方法都是针对特定类型的 PlanNode 设计的。例如,visitProject 是处理 ProjectNode 类型的节点,visitOutput 是处理 OutputNode 类型的节点。当 PlanNode 的类型与某个 visit* 方法匹配时,该方法就会被调用。
2. 递归遍历:Rewriter 通常会递归地遍历查询计划树。当它访问到一个节点时,会根据节点的具体类型调用相应的 visit* 方法。如果该节点类型没有特定的 visit* 方法,通常会调用一个更通用的 visitPlan 方法。
3. 方法执行:在 visit* 方法中,Rewriter 可以根据需要修改或替换当前节点。例如,它可能会添加新的节点,修改节点的属性,或者调整子节点的结构。

示例
假设有一个查询计划树,其中包含 OutputNode, ProjectNode, 和 FilterNode。Rewriter 在处理这个树时,会:
对于 OutputNode,调用 visitOutput 方法。
对于 ProjectNode,调用 visitProject 方法。
对于 FilterNode(如果没有特定的 visitFilter 方法),调用 visitPlan 方法。

LimitPushDown

//Limit下推优化器, 功能:判断是否可以下推Limit条件,以筛除数据,提高运行速度,减少资源消耗public class LimitPushDown implements PlanOptimizer.visitPlan
PlanNode rewrittenNode = context.defaultRewrite(node);//遍历所有node,调用rewrite方法
node.getSources().stream().map(child -> rewrite(child, context))//获取当前node的全局Limit条件是否存在,!=null则不能直接替换,生成LimitNode对象,返回LimitContext limit = context.get();
if (limit != null) {// Drop in a LimitNode b/c we cannot push our limit down any furtherrewrittenNode = new LimitNode(idAllocator.getNextId(), rewrittenNode, limit.getCount(), limit.isPartial());
}//替换原树
replaceChildren(node, children);/*
如果 LimitNode 的上游还有一个 LimitNode 那么把这两个 LimitNode 进行合并。
如果合并之后要 LimitNode 的count 是 0,那么直接把这个 LimitNode 节点换成一个空的 Values 节点。
如果 LimitNode 的上游有一个 TopN 节点,那么把 Limit 和 TopN 节点进行合并。
如果碰到 Union 节点,那么把 Limit 节点推到 Union 下面去。*///谓词下推,与Limit逻辑基本一致
public class PredicatePushDown implements PlanOptimizer


 

AddExchanges

public class AddExchanges implements PlanOptimizer
plan.accept(new Rewriter(idAllocator, symbolAllocator, session), PreferredProperties.any());/*介绍:划分子图,为查询计划添加交换节点,确保任务正确分布在各个节点,直接影响SubPlan 的划分
功能:1.确保数据正确分布。例如 groupby 根据hash分布至不同节点上2.优化节点分布,减少网络传输,提高查询效率流程:1. 分析查询计划:优化器首先分析当前的查询计划,识别出需要数据交换的操作。这包括但不限于聚合、连接、排序等操作。2. 确定数据分布需求:对于每个操作,AddExchanges 确定数据需要如何分布以满足操作需求。例如,对于一个基于某个键的聚合操作,数据需要根据该键进行哈希分布。3. 插入交换节点:根据确定的数据分布需求,AddExchanges 在查询计划中适当的位置插入交换节点。这些节点负责在执行时将数据从一个节点传输到另一个节点。4. 优化数据路径:在添加交换节点的同时,AddExchanges 还会尝试优化数据传输的路径,减少跨节点的数据移动,优化整体查询性能。5. 递归处理:由于查询计划可能非常复杂,包含多层嵌套的操作,AddExchanges 通常需要递归地处理整个查询计划树,确保所有需要的数据交换都被正确处理。
*/ExhangeNode.Type:GATHER          收集类型。出现在局部聚合或Coordinator OutPut  REPARTITION     repartition类型。按hashcode分发至指定节点,出现在groupby或join时REPLICATE       拷贝类型。出现在小表join大表,广播时
ExhangeNode.Scope:LOCAL 预聚合REMOTE 任务切分,生成SubPlan

迭代优化器 IterativeOptimizer :

迭代优化器是在基础优化器开发基础上,做的代码重构。/*
Memo对象背景:
源码中,为保证程序稳定,避免潜在问题。PlanNode对象是不可变的(immutable),但每次修改则需要重构树,性能有所下降且修改麻烦。为解决这个问题,则声明了一个Memo可变对象。
Memo中,PlanNode被包装成 GroupReference(不可变),GroupReference包含Group(可变),Group包含PlanNode(用于修改优化)。通过遍历GroupReference修改PlanNode。
Group 伴随引用计数,如被优化或不被任何Group引用,则需要清理掉// 增加引用计数
incrementReferenceCounts(node, group);// 更新节点
getGroup(group).membership = node;// 减少引用计数,如果为0,则删除
decrementReferenceCounts(old, group);*///流程:
optimize:new Memo();new PlanNodeMatcher();exploreGroup(memo.getRootGroup(), context, matcher);//遍历Rule
Iterator<Rule<?>> possiblyMatchingRules = ruleIndex.getCandidates(node).iterator();
//Match  getPattern()
Rule.Result result = transform(node, rule, matcher, context);
//对应规则逻辑  rule.apply()
result = rule.apply(match.value(), match.captures(), ruleContext(context));

关于Join优化器

distributed_join 是否使用分布式Join

distributed_sort 是否使用分布式Sort

join_distribution_type 分布式Join策略类型

join_reordering_strategy  重排序策略

max_reordered_joins 重排序组内容许Join表的最大值

push_aggregation_through_join  是否在Join前预聚合

task.max-partial-aggregation-memory  预聚合HashTable内存大小,默认16M

ReorderJoins 重排序优化规则:影响Join执行顺序,基于CBO生成

1. 枚举所有可能的连接顺序
chooseJoinOrder 方法首先会枚举所有可能的连接顺序。
2. 计算每种连接顺序的成本
对于每一种可能的连接顺序,Presto 会计算其成本。成本的计算通常基于多个因素,如数据大小、过滤器的选择性、连接键的分布等。Presto 使用成本模型来估算不同连接顺序的执行成本。
3. 选择最低成本的连接顺序
在所有可能的连接顺序中,chooseJoinOrder 方法会选择成本最低的一个。这是通过比较每种连接顺序的预估成本来实现的。
4. 递归优化每个子连接
一旦选择了一个连接顺序,chooseJoinOrder 方法会递归地优化每个子连接。这意味着对于每个连接操作,它会再次调用自身来优化该连接操作中涉及的表的连接顺序。
5. 应用最优连接顺序
最后,选择的连接顺序会被应用到查询计划中。这可能涉及到重构原始的查询计划树,以便按照选择的顺序执行连接

注意:重排优化选择成本最低的顺序即最优顺序,Hive不支持直方图,因此无法使用该优化

EliminateCrossJoins : 对表之间的Join顺序重新排列,避免笛卡尔积问题

InnerJoin包裹CrossJoin 通过更改执行顺序,优化为InnerJoin包裹InnerJoin

DetermineJoinDistributionType 控制分布式优化规则:用于决定Join类型,基于CBO生成

Partial Aggregations  预聚合优化器

通过push_partial_aggregation_through_join配置使用(默认:关闭)。预聚合并不影响数据量。如果hash分布特别散时,反而会使查询变慢。

关于CBO(cost-based optimizer)

总结:

基础优化器,通过vistor模式重写了各种方法。当对应PlanNode类型访问时,要执行的其自定义优化方法,最后判断是否符合更新规则,更新原树结构。
迭代优化器, 定义了各种规则(Rule),模式匹配(PlanNodeMatcher)当前树是否符合规则,符合则调用对应规则进行优化,输入原树,输出新树。

区别:
基础优化器需要定义各种Node类型,实现vistor对象,重新visit*方法
迭代优化器编写Rule,重写getPattern(匹配规则)、apply(优化方法)即可,同时还可以控制由Session参数,决定是否启用某个优化规则(EliminateCrossJoins只有在满足join条件时才运行)。

备注:

validate 验证  

extract 提取  

phase 阶段

SymbolAllocator 符号分配器

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

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

相关文章

docker容器中解决中文乱码

1. 找到dockerfile文件 2. 编辑Dockerfile 添加 ENV LANG en_US.UTF-8 ENV LANGUAGE en_US:en ENV LC_ALL en_US.UTF-8 3. 生成新的镜像文件 FROM java17_yinpeng:latest MAINTAINER YP <2064676101QQ.COM> ADD jiquan_online_chat.jar jiquan_online_chat #CM…

Socks5代理IP有什么特点:

小熊IPSocks5代理IP比其他类型的代理具有更多的灵活性和安全性。SOCKS5代理的另一个优点是您可以将其用于任何类型的流量&#xff08;TCP或UDP&#xff09;。您可以有选择地隐藏流量的特定部分&#xff08;基于应用程序&#xff09;&#xff0c;从基于TCP的连接&#xff08;如H…

【HarmonyOS】取消页面转场动画

【HarmonyOS】取消页面转场动画 问题背景&#xff1a; 当A页面切换至B页面时&#xff0c;系统会自带左右进场退场的动画效果。一般来说&#xff0c;该效果是ok的&#xff0c;但是在特殊场景下&#xff0c;例如&#xff1a; A页面跳到B页面&#xff0c;又跳到C页面。C页面直接返…

存储型XSS

前言 什么是存储型xss&#xff1a; 提交恶意xss数据&#xff0c;存入数据库中&#xff0c;访问时触发。 存储型xss和反射型xss区别&#xff1a; 存储型存入数据库中&#xff0c;可持续时间长&#xff0c;而反射型持续时间短&#xff0c;仅对本次访问有影响&#xff0c;反射型一…

中华活页文选高中版投稿发表

《中华活页文选&#xff08;高中版&#xff09;》创刊于1960年&#xff0c;是中宣部所属中国出版传媒股份有限公司主管、中华书局主办的国家级基础教育期刊&#xff0c;曾获得“中国期刊方阵双效期刊”、国家新闻出版广电总局推荐的“百种优秀报刊”等荣誉称号。本刊以高中学科…

TCP连接优化

TCP连接未释放 断开连接后TCP有两个状态&#xff1a; 一个是TIME_WAIT&#xff0c;一个是CLOSE_WAIT&#xff0c;是不同的两个状态 TIME_WAIT&#xff1a;出现在主动断开方&#xff0c;发出最后一个ACK后 CLOSE_WAIT&#xff1a;出现在被动断开方&#xff0c;收到主动断开方的…

Day 6:2981. 找出出现至少三次的最长特殊子字符串 I

Leetcode 2981. 找出出现至少三次的最长特殊子字符串 I 给你一个仅由小写英文字母组成的字符串 s 。 如果一个字符串仅由单一字符组成&#xff0c;那么它被称为 特殊 字符串。例如&#xff0c;字符串 “abc” 不是特殊字符串&#xff0c;而字符串 “ddd”、“zz” 和 “f” 是特…

数据容器:set(集合) 更新啦!

数据容器&#xff1a;set&#xff08;集合&#xff09; 1.集合的定义方式 {元素, 元素, 元素} # 定义集合 my_set {"欣欣向荣", "嘉嘉", "red", "欣欣向荣", "嘉嘉", "red", "欣欣向荣", "嘉嘉…

Spring BeanPostProcessor的前置魔法:揭秘与启迪

1. 引言 Spring框架的BeanPostProcessor是一个强大的扩展点&#xff0c;允许开发者在Spring IoC容器实例化、配置和初始化bean前后插入自定义逻辑。其中&#xff0c;前置方法postProcessBeforeInitialization是BeanPostProcessor接口中的一个重要方法&#xff0c;它在bean的初…

数据库中的视图:定义、作用及使用场景

在数据库的世界中&#xff0c;视图&#xff08;View&#xff09;是一个虚拟的表&#xff0c;其内容由查询定义。视图同真实的表一样&#xff0c;包含一系列带有名称的列和行数据。但是&#xff0c;视图并不在数据库中以存储的数据值集形式存在。行和列数据来自由定义视图的查询…

读《营销管理》之三大市场结果

由于四大市场力量的存在&#xff0c;有形无形的改变着世界&#xff0c;在新的营销现实中&#xff0c;消费者、公司和竞争环境都经历了显著的变化&#xff0c;这些变化赋予了他们新的能力&#xff0c;并改变了他们互动的方式。读《营销管理》之四大市场力量-CSDN博客以下是详细解…

性能猛兽:OrangePi Kunpeng Pro评测!

1.引言 随着物联网和嵌入式系统的不断发展&#xff0c;对于性能强大、资源消耗低的单板计算机的需求也日益增加。在这个快节奏的技术时代&#xff0c;单板计算机已成为各种应用场景中不可或缺的组成部分&#xff0c;从家庭娱乐到工业自动化&#xff0c;再到科学研究&#xff0…

差分曼彻斯特编码详解

这是一种双向码&#xff0c;和曼彻斯特编码不同的是&#xff0c;这种码元中间的电平转换边只作为定时信号&#xff0c;不表示数据。数据的表示在于每一位开始处是否有电平转换&#xff1a;有电平转换则表示0&#xff0c;无则表示1。然后这就出现一个问题&#xff0c;很多小伙伴…

Vue2源码解析-生命周期

两个文件&#xff0c;一个html一个js <body><div id"app"></div> </body> <script src"./Vue.js"></script> <script>new Vue({el: #app,data: {str: "你好"},beforeCreate() {console.log(beforeCr…

App Inventor 2 低功耗蓝牙BLE 两种通信方式:扫描和广播

低功耗蓝牙&#xff0c;也称为蓝牙 LE 或简称 BLE&#xff0c;是一种类似于经典蓝牙的新通信协议&#xff0c;不同之处在于它旨在消耗更少的功耗&#xff0c;同时保持可比的功能。 因此&#xff0c;低功耗蓝牙是与耗电资源有限的物联网设备进行通信的首选。BluetoothLE 扩展需…

2023年简单易用的透明加密软件--安秉网盾企业数据防泄密方案

随着移动互联网的兴起&#xff0c;企业对对网络安全的需求日益增加&#xff0c;透明加密软件技术也是近些年企业对文件图纸防泄密的主要解决技术方案。但是在广大企业在使用透明加密技术做防泄密时因为自身对透明加密技术的不是很深入的了解&#xff0c;造成企业在使用过程中还…

DiffBIR论文阅读笔记

这篇是董超老师通讯作者的一篇盲图像修复的论文&#xff0c;目前好像没看到发表在哪个会议期刊&#xff0c;应该是还在投&#xff0c;这个是arxiv版本&#xff0c;代码倒是开源了。本文所指的BIR并不是一个single模型对任何未知图像degradation都能处理&#xff0c;而是用同一个…

数据结构(十)图

文章目录 图的简介图的定义图的结构图的分类无向图有向图带权图&#xff08;Wighted Graph&#xff09; 图的存储邻接矩阵&#xff08;Adjacency Matrix&#xff09;邻接表代码实现 图的遍历深度优先搜索&#xff08;DFS&#xff0c;Depth Fisrt Search&#xff09;遍历抖索过程…

【搜索方法推荐】高效信息检索方法和实用网站推荐

博主未授权任何人或组织机构转载博主任何原创文章&#xff0c;感谢各位对原创的支持&#xff01; 博主链接 本人就职于国际知名终端厂商&#xff0c;负责modem芯片研发。 在5G早期负责终端数据业务层、核心网相关的开发工作&#xff0c;目前牵头6G算力网络技术标准研究。 博客…

同时执行多个python脚本扫描,报如下错误,原因为文件越大读取到内存占用内存越多。

killed nohup python $file unable to fork process cannot allocate memory ls: error while loading shared libraries: libdl.so.2 failed to map segment from shared object cannot allocate memory python进程被系统或者某个用户通过 kill 命令强制终止了