跳转至

直方图概述

MySQL8.0开始支持索引之外的数据分布统计信息可选项。它就是直方图(Histogram)。直方图(histogram),直译就是柱状图,国内多翻译为直方图。

直方图不是图,是对表的某个字段数据分布的统计,这种数据统计是基于某字段的实际存储数据分布得出的。

这种分布统计可以帮助查询优化器掌握字段真实的情况,从而得出更高效而切合实际的执行计划。

在有直方图之前,优化器对某字段的数据分布预估有可能是不准确的,甚至可能和实际情况差距比较大,错误的预估会导致不高效的执行计划。

直方图通过估算查询谓词的选择率,以便选择合适的执行计划,也让SQL优化有了更多手段。在DB中,优化器负责将SQL转换为很多个不同的执行计划,然后从中选择一个最优的来实际执行。但是有时候优化器选择的最终计划有可能随着DB环境的变化不是最优的,这就导致了查询性能不是很好。

比如,优化器无法准确的知道每张表的实际行数以及参与过滤条件的列有多少个不同的值。当然不同类型的索引也可以解决这个问题,但是你不能每个列都建索引吧?

如果一张表有100个字段,那全字段索引将会拖死对这张表的写入。而且但索引维护的代价更高,索引统计信息也有不可靠的时候,例如存在数据倾斜,或者统计延迟等问题,索引要保持更新,而直方图可以按需手动更新。此时,直方图就是相对来说,开销较小的方法。当然,直方图还是无法代替索引,只在一些特定的场景里比较有用

直方图就是在 MySQL 中为某张表的某些字段提供了一种数值分布的统计信息。比如字段NULL的个数,每个不同值出现的百分比,最大值,最小值等等。

如果我们用过了MySQL的分析型引擎brighthouse,那对这个概念太熟悉了。

SELECT *
FROM 
    customer JOIN orders ON customer.cust_id = orders.customer_id
 WHERE
    customer.balance < 1000 AND
  orders.total > 10000

在优化过程中,为了决定 customerorders 两表的 join order,我们需要哪个表经过 where 条件(customers.balance < 1000 和 orders.total > 10000)筛选后能生成更少的行数。这时,优化器不光需要知道两表的总行数,也需要知道每个表中符合条件的行数,即**查询谓词的选取率**。

在相应列既没有直方图也没有索引的情况下,MySQL 对选择率的估算为max((1/max_distinct_values),max_distinct_values),其中max_distinct_values的值为 0.1(where 条件为 = 时)或 0.333(where 条件为 < 或 > 时)。这种估算方式十分粗糙地忽略了列中数据的分布。​