基于calcite做傻瓜式的sql优化(二)

 上一篇:基于calcite做傻瓜式的sql优化(一)

因为主要想借助hive的思路来实现对sql的优化,所以这一篇主要是梳理一条sql在hive内部大概是什么样的生命周期

首先通过一张图看下,内部sql大概执行流:

 sql经过一系列的规则处理后,最后变成task tree,然后mapreduce通过task tree来执行job

接下来通过源码,看下是如何处理的!

另外我把编译好的hive(1.2.1版本)和hadoop(2.7.0版本)代码放在Git上,这样感兴趣的同学直接下载下来,就可以在本地debug跑

Hive编译后的源码:https://github.com/niutaofan/apache-hive-1.2.1-src.git
hadoop编译后的源码:链接:https://pan.baidu.com/s/1meF9MFHUAyY1Mk7mMOdqIg  密码:fwnh

1、大体流程

1)、Driver.compile 接收SQL , 然后通过:pd.parse(command)将SQL转换为ASTNode(这个过程包含了词法解析和语法解析)

  1.1、ParseDriver.parse接收到sql语句,然后通过:r = parser.statement();解析了词法和语法

  1.2、拿到解析后的HiveParser.statement_return,然后通过ASTNode tree = (ASTNode) r.getTree();获取到ASTNode

2)、通过sem.analyze(tree, ctx);从AST Node到Phsical Optimize这几个阶段,都是在SemanticAnalyzer.analyzeInternal()方法中进行的(语义解析、生成逻辑执行计划、优化逻辑执行计划等)

  2.1、拿到ASTNode之后,通过SemanticAnalyzer.analyzeInternal()进行优化;

  2.2、代码会调度到CalcitePlanner.analyzeInternal (这个方法内部会做 一个流程的判断:if (runCBO) 是否执行CBO优化),当然不管执行RBO还是CBO,最后调用的都是:SemanticAnalyzer.analyzeInternal()

  2.3、在SemanticAnalyzer.analyzeInternal()方法中,首先基于ASTNode做了各种规则优化,根据需求包括了笼统的:RBO和CBO的优化,最终返回Operator

    在Hive中,使用Calcite来进行核心优化,它将AST Node转换成QB,又将QB转换成Calcite的RelNode,在Calcite优化完成后,又会将RelNode转换成Operator Tree,说起来很简单,但这又是一条很长的调用链。

    Calcite优化的主要类是CalcitePlanner,更加细节点,是在CalcitePlannerAction.apply()这个方法,CalcitePlannerAction是一个内部类,包括将QB转换成RelNode,优化具体操作都是在这个方法中进行的。

  

2、一条sql的源码之路

如果想debug的方式走读源码,那么需要如下几个步骤:

第一步:启动本地的hadoop源码(NameNode和DataNode)

 第二步:启动hive的metastore服务

 第三步:启动(Debug方式)CliDriver类

根据上文提示, sql在客户端执行后,会在Driver.compile 接收SQL , 然后通过:pd.parse(command)将SQL转换为ASTNode(这个过程包含了词法解析和语法解析)

eg. 执行一段sql(sql的数据,提前放入hive了) , 看下hive是如何解析和优化的

select 
  * 
from 
  (
    select 
      Sname, 
      Sex, 
      Sage, 
      Sdept, 
      count(1) as num 
    from 
      student_ext 
    group by 
      Sname, 
      Sex, 
      Sage, 
      Sdept
  ) t1 
where 
  Sage > 10;

Driver.compile代码:

 上图比较重要的点:

ParseDriver

Hive使用的是antlr来做词法、语法的解析工作,最终生成一棵有语义的ast树
而在Hive中调用antlr类的代码org.apache.hadoop.hive.ql.parse.ParseDriver类,通过ParseDriver.parse 可以返回HiveParser.statement_return 

而这个HiveParser.statement_return通过强转,即可拿到ASTNode,如下图:

 ps:这块儿存在极大的性能问题,后续会提到并改进

######################################################思考############################################################################################

如果需求是快速实现对用户输入的sql进行词法和语法解析,以便达到自定义或者sql优化的需求,那么可不可以利用上述内容进行重构???

答案是肯定可以的,而且非常简单,只需要知道,hive在做sql的词法和语法解析,使用的是哪个包(org.apache.hadoop.hive.ql.parse)

然后开启一个新的工程,导入hive-exec包即可

第一步:maven导入依赖

 <dependency>
            <groupId>org.apache.hive</groupId>
            <artifactId>hive-exec-nt</artifactId>
            <version>1.2.1</version>
 </dependency>
 <dependency>
            <groupId>org.apache.hadoop</groupId>
            <artifactId>hadoop-common</artifactId>
            <version>2.7.1</version>
 </dependency>

第二步:代码编写 

import org.apache.hadoop.hive.ql.parse.ASTNode;
import org.apache.hadoop.hive.ql.parse.ParseDriver;
import org.apache.hadoop.hive.ql.parse.ParseException;
/**
 * Created by niutao
 */
public class Tests {
    public static void main(String[] args) {
        String sql = "SELECT `object_id`, `column1_id`, COUNT(DISTINCT `cookie`) AS `COOKIE`
" +
                "FROM `D_DSJ_INDEX_PDS`.`INDEX2_FLW_COOKIE_INTEREST_OBJECT_D_FACT`
" +
                "WHERE `dim_day` >= '2020-03-03' AND `dim_day` <= '2020-03-16' AND `series_id` = '692'
" +
                "GROUP BY `object_id`, `column1_id`
" +
                "ORDER BY COUNT(DISTINCT `cookie`) IS NULL DESC, COUNT(DISTINCT `cookie`) DESC
" +
                "LIMIT 200";
        //1、导入模仿hive,导入ParseDriver
        ParseDriver pd = new ParseDriver();
        //2、解析sql
        try {
            ASTNode ast = pd.parse(sql);
            //3、测试,打印解析树
            System.out.println(ast.dump());
        } catch (ParseException e) {
            e.printStackTrace();
        }
    }
}

打印 结果:

 通过以上方式,即可将sql解析出ASTNode

###################################################################################################################################################### 

接着之前的源码,看下在生成ASTNode之后 , 是如何根据ASTNode来做优化的;

请查看下一篇:基于calcite做傻瓜式的sql优化(三)

原文地址:https://www.cnblogs.com/niutao/p/14024383.html