zoukankan      html  css  js  c++  java
  • Hive SQL执行流程分析

    转自 http://www.tuicool.com/articles/qyUzQj 

    最近在研究Impala,还是先回顾下Hive的SQL执行流程吧。

    Hive有三种用户接口:

    cli (Command line interface) bin/hive或bin/hive –service cli 命令行方式(默认)
    hive-server/hive-server2 bin/hive –service hiveserver 或bin/hive –service hiveserver2 通过JDBC/ODBC和Thrift访问(Impala通过这种方式借用hive-metastore)
    hwi (Hive web interface) bin/hive –service hwi 通过浏览器访问

    在hive shell中输入“show tables;”实际执行的是:

    bin/hadoop jar hive/lib/hive-cli-0.9.0.jar org.apache.hadoop.hive.cli.CliDriver -e 'SHOW TABLES;'

    CLI入口函数:cli.CliDriver.main()

    读入参数->建立SessionState并导入配置->处理输入文件中指令CliDriver.processFile();或交互型指令CliDriver.processLine()->解析输入CliDriver.processCmd()

    (1)    如果是quit或者exit,退出

    (2)    以source开头的,读取外部文件并执行文件中的HiveQL

    (3)    !开头的命令,执行操作系统命令(如!ls,列出当前目录的文件信息)

    (4)    list,列出jar/file/archive

    (5)    其他命令,则生成调用相应的CommandProcessor处理,进入CliDriver.processLocalCmd()

    CliDriver.processLocalCmd()

    set/dfs/add/delete指令交给指定的CommandProcessor处理,其余的交给org.apache.hadoop.hive.ql.Driver.run()

    org.apache.hadoop.hive.ql.Driver类是查询的起点,run()方法会先后调用compile()和execute()两个函数来完成查询,所以一个command的查询分为compile和execute两个阶段。

    Compile

    (1)利用antlr生成的HiveLexer.java和HiveParser.java类,将HiveQL转换成抽象语法树(AST)。

    首先使用antlr工具将srcqlsrcjavaorgapachehadoophiveqlparsehive.g编译成以下几个文件:HiveParser.java, Hive.tokens, Hive__.g, HiveLexer.java

    HiveLexer.java和HiveParser.java分别是词法和语法分析类文件,Hive__.g是HiveLexer.java对应的词法分析规范,Hive.tokens定义了词法分析后所有的token。

    然后沿着“Driver.compile()->ParseDriver.parse(command, ctx)->HiveParserX.statement()->antlr中的API”这个调用关系把输入的HiveQL转化成ASTNode类型的语法树。HiveParserX是由antlr生成的HiveParser类的子类。

    (2)利用对应的SemanticAnalyzer类,将AST树转换成Map-reduce task

    a)         AST -> Operator DAG

    b)        优化Operator DAG

    c)         Oprator DAG -> Map-reduce task

    首先接着上一步生成的语法树ASTNode, SemanticAnalyzerFactory会根据ASTNode的token类型生成不同的SemanticAnalyzer (所有这些SemanticAnalyzer都继承自BaseSemanticAnalyzer)

    1)      ExplainSemanticAnalyzer

    2)      LoadSemanticAnalyzer

    3)      ExportSemanticAnalyzer

    4)      DDLSemanticAnalyzer

    5)      FunctionSemanticAnalyzer

    6)      SemanticAnalyzer

    然后调用BaseSemanticAnalyzer.analyze()->BaseSemanticAnalyzer. analyzeInternal()。

    下面以最常见的select * from table类型的查询为例,进入的子类是SemanticAnalyzer. analyzeInternal(),这个函数的逻辑如下:

    1)      doPhase1():将sql语句中涉及到的各种信息存储起来,存到QB中去,留着后面用。

    2)      getMetaData():获取元数据信息,主要是sql中涉及到的 表 和 元数据 的关联

    3)      genPlan():生成operator tree/DAG

    4)      optimize:优化,对operator tree/DAG 进行一些优化操作,例如列剪枝等(目前只能做rule-based optimize,不能做cost-based optimize)

    5)      genMapRedTasks():将operator tree/DAG 通过一定的规则生成若干相互依赖的MR任务

    Execute

    将Compile阶段生成的task信息序列化到plan.xml,然后启动map-reduce,在configure时反序列化plan.xml

    实例分析:

    在hive中有这样一张表:

    uid

    fruit_name

    count

    a

    apple

    5

    a

    orange

    3

    a

    apple

    2

    b

    banana

    1

    执行如下的查询:

    SELECT uid, SUM(count) FROM logs GROUP BY uid

    通过explain命令可以查看执行计划:

    EXPLAIN SELECT uid, SUM(count) FROM logs GROUP BY uid;

    依照hive.g的语法规则,生成AST如下

    ABSTRACT SYNTAX TREE:
    (
      TOK_QUERY
      (TOK_FROM (TOK_TABREF (TOK_TABNAME logs)))
      (
        TOK_INSERT
        (TOK_DESTINATION (TOK_DIR TOK_TMP_FILE))
        (
          TOK_SELECT
          (TOK_SELEXPR (TOK_TABLE_OR_COL uid))
          (TOK_SELEXPR (TOK_FUNCTION sum (TOK_TABLE_OR_COL count)))
        )
        (TOK_GROUPBY (TOK_TABLE_OR_COL uid))
      )
    )

    生成的执行计划operator tree/DAG如下:

    STAGE DEPENDENCIES:
      Stage-1 is a root stage
      Stage-0 is a root stage
    
    STAGE PLANS:
      Stage: Stage-1
        Map Reduce
          Alias -> Map Operator Tree:
            logs
              TableScan // 扫描表
                alias: logs
                Select Operator //选择字段
                  expressions:
                        expr: uid
                        type: string
                        expr: count
                        type: int
                  outputColumnNames: uid, count
                  Group By Operator //在map端先做一次聚合,减少shuffle数据量
                    aggregations:
                          expr: sum(count) //聚集函数
                    bucketGroup: false
                    keys:
                          expr: uid
                          type: string
                    mode: hash
                    outputColumnNames: _col0, _col1
                    Reduce Output Operator //输出key,value给reduce
                      key expressions:
                            expr: _col0
                            type: string
                      sort order: +
                      Map-reduce partition columns:
                            expr: _col0
                            type: string
                      tag: -1
                      value expressions:
                            expr: _col1
                            type: bigint
          Reduce Operator Tree:
            Group By Operator
              aggregations:
                    expr: sum(VALUE._col0) //聚合
              bucketGroup: false
              keys:
                    expr: KEY._col0
                    type: string
              mode: mergepartial
              outputColumnNames: _col0, _col1
              Select Operator //选择字段
                expressions:
                      expr: _col0
                      type: string
                      expr: _col1
                      type: bigint
                outputColumnNames: _col0, _col1
                File Output Operator //输出到文件
                  compressed: false
                  GlobalTableId: 0
                  table:
                      input format: org.apache.hadoop.mapred.TextInputFormat
                      output format: org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat
    
      Stage: Stage-0
        Fetch Operator
          limit: -1

    Hive优化策略:

    1. 去除查询中不需要的column

    2. Where条件判断等在TableScan阶段就进行过滤

    3. 利用Partition信息,只读取符合条件的Partition

    4. Map端join,以大表作驱动,小表载入所有mapper内存中

    5. 调整Join顺序,确保以大表作为驱动表

    6. 对于数据分布不均衡的表Group by时,为避免数据集中到少数的reducer上,分成两个map-reduce阶段。第一个阶段先用Distinct列进行shuffle,然后在reduce端部分聚合,减小数据规模,第二个map-reduce阶段再按group-by列聚合。

    7. 在map端用hash进行部分聚合,减小reduce端数据处理规模。

    参考文献:

    http://fatkun.com/2013/01/hive-group-by.html

  • 相关阅读:
    WebSocket
    牛人
    ECSHOP+wamp
    数据结构之-----------排序
    DRGS指标计算方法
    Oracle 11g安装教程
    JavaScript入门
    多态
    类的继承
    上传工具类
  • 原文地址:https://www.cnblogs.com/cxzdy/p/4936909.html
Copyright © 2011-2022 走看看