天天看點

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>