天天看点

MySQL · 特性分析 · 直方图的实现与分析

直方图会持久化存储到一个新的系统表 mysql.column_stats,表名与 mariadb 的一样,但是定义是不同的。直方图的主要数据保存在一个 json 类型的名为 histogram 的列中。因为 8.0 的字典表都采用了 innodb 引擎,这个表也不例外。

该特性支持所有的数据类型,包括数值类型、字符串、大对象、枚举类型等,也支持 generated column。

执行 analyze table [table] update histograms 命令可以产生表上各列的直方图,默认情况下这些信息会被复制到备库。

在文件 scripts/mysql_systemtables.sql 中可以看到该表的定义:

下面是这两种直方图的示例。

mysql 8.0 的代码做过不少重整,目录结构也比以前清楚多了。直方图的源代码都在目录sql/histograms 下,包括以下文件。

equi_height_bucket.cc

equi_height_bucket.h

equi_height.cc

equi_height.h

histogram.cc

histogram.h

singleton.cc

singleton.h

对应的单元测试文件为:unittest/gunit/histograms-t.cc。可以看到,代码用到了 c++11 的一些特性,并且还写了比较完整的单元测试,可读性很好。代码主要部分是这三个类:直方图的基类 histogram,以及实现等宽直方图、等高直方图的两个类 singleton 和 equi_height。

对外的主要接口是创建直方图的函数:

输入的数据需要放到一个 map 里头,表示每个值以及对应的出现次数,map 是按照值排序的。直方图一般不会对表中的所有数据逐行进行分析建立,这样做的代价太高了;很多实现都是通过对数据采样进行的。因此,这里用 map 而不是 iterator 也是比较自然的。如果桶的个数(num_buckets)比不同值的个数要大,则自动选择创建一个等宽直方图;否则创建一个等高直方图。

两种直方图的创建逻辑都比较简单,可以参看:

singleton<t>::build~histogram~() 和 equi~height~<t>::build~histogram~()。

通过参考资料中的内容,与 oracle、mariadb 做个对比,很容易发现 mysql 8.0 目前实现的直方图还只是提供了最基础的功能,还不能用来改进查询执行计划。

<a href="https://jira.mariadb.org/browse/mdev-4145">take into account the selectivity</a>

<a href="https://mariadb.com/kb/en/mariadb/histogram-based-statistics">histogram based statistics</a>

<a href="https://dev.mysql.com/worklog/task/?id=8706">wl#8706: persistent storage of histogram data</a>

<a href="https://dev.mysql.com/worklog/task/?id=8707">wl#8707: classes/structures for histograms</a>

<a href="http://allthingsoracle.com/histograms-part-1-why/">histograms part 1</a>

<a href="http://allthingsoracle.com/histograms-pt-2/">histograms part 2</a>

<a href="http://allthingsoracle.com/histograms-part-3-when/">histograms part 3</a>