zoukankan      html  css  js  c++  java
  • 基于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优化(三)

  • 相关阅读:
    Android Studio 开发
    Jsp编写的页面如何适应手机浏览器页面
    电影
    Oracle 拆分列为多行 Splitting string into multiple rows in Oracle
    sql server 2008 自动备份
    WINGIDE 激活失败
    python安装 错误 “User installations are disabled via policy on the machine”
    ble编程-外设发送数据到中心
    iOS开发-NSString去掉所有换行及空格
    ios9 字符串与UTF-8 互相转换
  • 原文地址:https://www.cnblogs.com/niutao/p/14024383.html
Copyright © 2011-2022 走看看