基於calcite做傻瓜式的sql優化(一)


 

 

我們要做的事情大概分3步:

1、需求的描述(主要把問題點拋出來)

2、解決如何優化sql性能的問題(hive關於一條sql的生命周期源碼的分析),也就是如何對你的sql進行RBO和CBO的優化

3、解決如何自動識別sql元數據的問題(antlr關於如何深度優先遍歷語法樹)

 

背景:

我們有一套智能中台系統,可以基於配置化的方式就可以做出各種圖表。說白了就是可以快速給業務通過圖表的方式展現數據

需求:

通過配置來快速展現數據固然是好的事情,但稍微思考一下其實也是通過配置的方式來生成sql;
那么生成的這個sql性能不見得會很好吧?(其實會非常的不好)  

比如,我們通過配置的方式生成的sql大概這個樣子:

select 
  t0.tree_id, 
  sum(t0.gap) as num 
from 
  (
    SELECT 
      w.tree_id, 
      w.gap, 
      r.executed_sql 
    FROM 
      data_middleground.view_mkt_node_kpi_warning w 
      JOIN data_middleground.view_mkt_node_result r ON w.tree_id = r.tree_id 
    WHERE 
      w.warning_status = 0 
      and r.is_del = 0
  ) t0 
where 
  t0.gap > 1 
group by 
  t0.tree_id 
order by 
  tree_id desc

花一分鍾仔細看下這個sql,會發現其實很爛,性能點在:

1、表關聯的時候,謂詞沒有下推
2、多個謂詞分別出現在關聯和聚合的地方,沒有做過濾合並和下推
3、有聚合操作,是否可以聚合下推?

爛sql的執行計划:

LogicalSort(sort0=[$0], dir0=[DESC])
  LogicalAggregate(group=[{0}], num=[SUM($1)])
    LogicalProject(tree_id=[$0], gap=[$1])
      LogicalFilter(condition=[>($1, 1)])
        LogicalProject(tree_id=[$0], gap=[$1], executed_sql=[$4])
          LogicalFilter(condition=[AND(=($2, 0), =($5, 0))])
            LogicalJoin(condition=[=($0, $3)], joinType=[inner])
              EnumerableTableScan(table=[[data_middleground, view_mkt_node_kpi_warning]])
              EnumerableTableScan(table=[[data_middleground, view_mkt_node_result]])

 

那么能否通過一套代碼處理后,讓“爛sql1”進入代碼,出來后是“好sql2”

先看下成果,優化后的sql:

SELECT 
  `t0`.`tree_id`, 
  SUM(`t0`.`gap`) AS `num` 
FROM 
  (
    SELECT 
      * 
    FROM 
      `data_middleground`.`view_mkt_node_result` 
    WHERE 
      `is_del` = 0
  ) AS `t` 
  INNER JOIN (
    SELECT 
      * 
    FROM 
      `data_middleground`.`view_mkt_node_kpi_warning` 
    WHERE 
      `warning_status` = 0 
      AND `gap` > 1
  ) AS `t0` ON `t`.`tree_id` = `t0`.`tree_id` 
GROUP BY 
  `t0`.`tree_id` 
ORDER BY 
  `t0`.`tree_id` IS NULL DESC, 
  `t0`.`tree_id` DESC

請花一分鍾看下sql,會發現這真TM是個好的sql;

執行計划:

LogicalSort(sort0=[$0], dir0=[DESC])
  LogicalAggregate(group=[{0}], num=[SUM($1)])
    LogicalProject(tree_id=[$0], gap=[$1])
      LogicalProject(tree_id=[$0], gap=[$1], executed_sql=[$4])
        LogicalJoin(condition=[=($0, $3)], joinType=[inner])
          LogicalFilter(condition=[AND(=($2, 0), >($1, 1))])
            EnumerableTableScan(table=[[data_middleground, view_mkt_node_kpi_warning]])
          LogicalFilter(condition=[=($2, 0)])
            EnumerableTableScan(table=[[data_middleground, view_mkt_node_result]])

 

那么如何實現上面的功能呢?可以參考spark、hive、druid等,他們是如何做的sql優化。這里我參考的是hive;

那么接下來通過走讀hive源碼的方式來看下,hive是如何處理一條sql的【請看下一篇:基於calcite做傻瓜式的sql優化(二)

 

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM