最近在研究Impala,仍是先回顧下Hive的SQL執行流程吧。html
Hive有三種用戶接口:java
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;」實際執行的是:web
bin/hadoop jar hive/lib/hive-cli-0.9.0.jar org.apache.hadoop.hive.cli.CliDriver -e 'SHOW TABLES;'
CLI入口函數:cli.CliDriver.main()sql
讀入參數->創建SessionState並導入配置->處理輸入文件中指令CliDriver.processFile();或交互型指令CliDriver.processLine()->解析輸入CliDriver.processCmd()shell
(1) 若是是quit或者exit,退出express
(2) 以source開頭的,讀取外部文件並執行文件中的HiveQLapache
(3) !開頭的命令,執行操做系統命令(如!ls,列出當前目錄的文件信息)瀏覽器
(4) list,列出jar/file/archiveapp
(5) 其餘命令,則生成調用相應的CommandProcessor處理,進入CliDriver.processLocalCmd()wordpress
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