基于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优化(二)

 

  

posted @ 2020-11-15 22:53  niutao  阅读(2165)  评论(0编辑  收藏  举报