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

3. 修改参数配置后，单击"保存"，根据界面提示操作后，等待配置保存成功。
4. Spark服务端配置更新后，如果"配置状态"为"配置过期"，则需重启组件以使配置生效。 
   图1修改Spark配置   
   ![](https://support.huaweicloud.com/cmpntguide-lts-mrs/zh-cn_image_0000002339002417.png "点击放大")
   在Spark服务概览页面，选择"更多 \> 重启服务/滚动重启服务"，验证管理员密码后，等待服务重启成功。
   如果使用Spark客户端提交任务，修改了集群的参数"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"后，需要重新下载客户端才能使配置生效，请参考[使用MRS客户端](https://support.huaweicloud.com/cmpntguide-lts-mrs/mrs_01_2126.html)。
   ![](https://support.huaweicloud.com/cmpntguide-lts-mrs/public_sys-resources/warning_3.0-zh-cn.png)
   组件重启期间将无法对外提供服务，可能会影响集群的上层业务正常运行，请在业务空闲期或确认操作无影响后再执行本操作。
   
   
 
