
# 配置列统计值直方图Histogram用以增强CBO准确度
#### 配置场景
Spark优化sql的执行，一般的优化规则都是启发式的优化规则，启发式的优化规则，仅仅根据逻辑计划本身的特点给出优化，没有考虑数据本身的特点，也就是未考虑算子本身的执行代价。Spark在2.2中引入了基于代价的优化规则（CBO）。CBO会收集表和列的统计信息，结合算子的输入数据集来估计每个算子的输出条数以及字节大小，这些就是执行一个算子的代价。
CBO会调整执行计划，来最小化端到端的查询时间，中心思路2点：
- 尽早过滤不相关的数据。
- 最小化每个算子的代价。
CBO优化过程分为2步：
1. 收集统计信息。
2. 根据输入的数据集估算特定算子的输出数据集。
表级别统计信息包括：记录条数；表数据文件的总大小。
列级别统计信息包括：唯一值个数；最大值；最小值；空值个数；平均长度；最大长度；直方图。
有了统计信息后，就可以估计算子的执行代价了。常见的算子包括过滤条件Filter算子和Join算子。
直方图为列统计值的一种，可以直观地描述列数据的分布情况，将列的数据从最小值到最大值划分为事先指定数量的槽位（bin），计算各个槽位的上下界的值，使得全部数据都确定槽位后，所有槽位中的数据数量相同（等高直方图）。有了数据的详细分布后，各个算子的代价估计能更加准确，优化效果更好。
该特性可以通过下面的配置项开启：
**spark.sql.statistics.histogram.enabled**：指定是否开启直方图功能，默认为false。
#### 配置参数
登录FusionInsight Manager系统，选择"集群 \> *待操作集群的名称* \> 服务 \> Spark2x \> 配置"，单击"全部配置"，搜索以下参数。
| **参数**                                       | **说明**                                                            | **默认值** | 取值范围           |
|:---|:---|:---|:---|
| spark.sql.cbo.enabled                        | 开启CBO来估计执行计划的统计值。                                                 | false   | \[true,false\] |
| spark.sql.cbo.joinReorder.enabled            | 开启CBO连接重排序。                                                       | false   | \[true,false\] |
| spark.sql.cbo.joinReorder.dp.threshold       | 动态规划算法中允许的最大的join节点数量。                                            | 12      | \>=1           |
| spark.sql.cbo.joinReorder.card.weight        | 在重连接执行计划代价比较中维度（行数）所占的比重：行数 \* 比重 + 文件大小 \*（1 - 比重）。              | 0.7     | 0-1            |
| spark.sql.statistics.size.autoUpdate.enabled | 开启当表的数据发生变化时，自动更新表的大小信息。注意如果表的数据文件总数量非常多时，这个操作会非常耗费资源，减慢对数据的操作速度。 | false   | \[true,false\] |
| spark.sql.statistics.histogram.enabled       | 开启后，当统计列信息时，会生成直方图。直方图可以提高估计准确度，但是收集直方图信息会有额外工作量。                 | false   | \[true,false\] |
| spark.sql.statistics.histogram.numBins       | 生成的直方图的槽位数。                                                       | 254     | \>=2           |
| spark.sql.statistics.ndv.maxError            | 在生成列级别统计信息时，HyperLogLog++算法允许的最大估计误差。                             | 0.05    | 0-1            |
| spark.sql.statistics.percentile.accuracy     | 在生成等高直方图时百分位估计的准确率。该值越大意味着越准确。估计错误值可以通过（1.0 / 百分位估计的准确率）来得到。      | 10000   | \>=1           |
   
![](https://support.huaweicloud.com/cmpntguide-mrs/public_sys-resources/note_3.0-zh-cn.png)
- 如果希望直方图可以在CBO中生效，需要满足下面的条件：
  - spark.sql.statistics.histogram.enabled : true，默认是false，修改为true开启直方图功能。
  
  - spark.sql.cbo.enabled : true，默认为false，修改为true开启CBO。
  
  - spark.sql.cbo.joinReorder.enabled : true，默认为false，修改为true开启连接重排序。
   
- 若使用客户端提交任务，"spark.sql.cbo.enabled"、"spark.sql.cbo.joinReorder.enabled"、"spark.sql.cbo.joinReorder.dp.threshold"、"spark.sql.cbo.joinReorder.card.weight"、"spark.sql.statistics.size.autoUpdate.enabled"、"spark.sql.statistics.histogram.enabled"、"spark.sql.statistics.histogram.numBins"、"spark.sql.statistics.ndv.maxError"、"spark.sql.statistics.percentile.accuracy"参数修改后需要重新下载客户端才能生效。
 
