阿里云-云小站(无限量代金券发放中)
【腾讯云】云服务器、云数据库、COS、CDN、短信等热卖云产品特惠抢购

MySQL 8.0 中统计信息直方图的尝试

491次阅读
没有评论

共计 5282 个字符,预计需要花费 14 分钟才能阅读完成。

直方图是表上某个字段在按照一定百分比和规律采样后的数据分布的一种描述,最重要的作用之一就是根据查询条件,预估符合条件的数据量,为 sql 执行计划的生成提供重要的依据

在 MySQL 8.0 之前的版本中,MySQL 仅有一个简单的统计信息却没有直方图,没有直方图的统计信息可以说是没有任何意义的。

MySQL 8.0 新特性之一就是开始支持统计信息的直方图,这个概念很早就提出来了,抽空具体尝试了一下使用方法。

照旧,直接上例子,造数据,创建一个测试环境

create table test
(
    id int auto_increment primary key,
    name varchar(100),
    create_date datetime ,
    index (create_date desc)
);

USE `db01`$$

DROP PROCEDURE IF EXISTS `insert_test_data`$$

CREATE DEFINER=`root`@`%` PROCEDURE `insert_test_data`()
BEGIN
    DECLARE v_loop INT;
    SET v_loop = 100000;
    WHILE v_loop>0 DO
        INSERT INTO test(NAME,create_date)VALUES (UUID(),DATE_ADD(NOW(),INTERVAL -RAND()*100000 MINUTE) );
        SET v_loop = v_loop – 1;
    END WHILE;
END$$

DELIMITER ;

MySQL 中统计信息的创建,不同于 MSSQL,MySQL 统计信息不依赖于索引,需要单独创建,语法如下

– 创建字段上的统计直方图信息
ANALYZE TABLE test UPDATE HISTOGRAM ON create_date,name WITH 16 BUCKETS;
– 删除字段上的统计直方图信息
ANALYZE TABLE test DROP HISTOGRAM ON create_date

1,可以一次性创建多个字段的统计信息,系统会逐个创建列出的字段上的统计信息,统计信息不依赖于索引,这一点与 MSSQL 不同(当然 MSSQL 也可以抛开索引独立创建统计信息)
2,BUCKETS 值是一个必须提供的参数,默认值为 1000,范围是 1 -1024,这一点也不同与 MSSQL 也不一样,MSSQL 是有一个类似的最大值为 200 的步长(step)字段
3,一般来说,数据量较大的情况下,对于不重复或者重复性不高的数据,BUCKETS 值越大,描述出来的统计信息越详细
4,统计信息的具体内容在 information_schema.column_statistics 中,但是可读性并不好,可以根据需求自行解析(出来一种自己喜欢的格式)

与 sqlserver 中的统计信息一样,理论上,在准确性与取样百分比(BUCKETS)是成正比的,当然生成统计信息的代价也就越大,
至于 BUCKETS 与统计信息的取样百分比,以及综合代价,笔者暂时没有找到相关的资料。

如下是通过 ANALYZE TABLE test UPDATE HISTOGRAM ON create_date WITH 4 BUCKETS; 创建的统计信息直方图
可以发现直方图的 HISTOGRAM 字段是一个 JSON 格式的字符串,可读性并不好。

MySQL 8.0 中统计信息直方图的尝试

想到了 sqlserver 中 DBCC SHOW_STATISTICS 的直方图信息,如下的格式,直方图中的数据分布情况看起来非常清晰直观

MySQL 8.0 中统计信息直方图的尝试

于是就做了一个 MySQL 直方图的格式转换,说白了就是解析 information_schema.column_statistics 表中的 HISTOGRAM 字段中的 JSON 内容
如下,一个简单的解析直方图统计信息 json 数据的存储过程, 参数分别是库名,表名,字段名

DELIMITER $$

USE `db01`$$

DROP PROCEDURE IF EXISTS `parse_column_statistics`$$

CREATE DEFINER=`root`@`%` PROCEDURE `parse_column_statistics`(
    IN `p_schema_name` VARCHAR(200),
    IN `p_table_name` VARCHAR(200),
    IN `p_column_name` VARCHAR(200)
)
BEGIN
   
    DECLARE v_histogram TEXT;
    — get the special HISTOGRAM
    SELECT HISTOGRAM->>’$.”buckets”‘ INTO v_HISTOGRAM
    FROM  information_schema.column_statistics
    WHERE schema_name =  p_schema_name
    AND table_name = p_table_name
    AND column_name = p_column_name;
   
    — remove the first and last [and] char
    SET v_histogram = SUBSTRING(v_HISTOGRAM,2,LENGTH(v_HISTOGRAM)-2);

    DROP TABLE IF EXISTS t_buckets ;
    CREATE TEMPORARY TABLE t_buckets
    (
        id INT AUTO_INCREMENT PRIMARY KEY,
        buckets_content VARCHAR(500)
    );
   
    — split by “],” and get single bucket content   
    WHILE (INSTR(v_histogram,’],’)>0) DO
        INSERT INTO t_buckets(buckets_content)
        SELECT SUBSTRING(v_histogram,1,INSTR(v_histogram,’],’));
        SET v_HISTOGRAM = SUBSTRING(v_histogram,INSTR(v_histogram,’],’)+2,LENGTH(v_histogram));   
    END WHILE;

    INSERT INTO t_buckets(buckets_content)
    SELECT v_histogram;
   
    — get the basic statistics data
    WITH cte AS
    (
        SELECT
        HISTOGRAM->>’$.”last-updated”‘ AS last_updated,
        HISTOGRAM->>’$.”number-of-buckets-specified”‘ AS number_of_buckets_specified
        FROM INFORMATION_SCHEMA.COLUMN_STATISTICS
        WHERE schema_name =  p_schema_name
        AND table_name = p_table_name
        AND column_name = p_column_name
    )
    SELECT
        CASE WHEN id = 1 THEN p_schema_name ELSE ” END AS schema_name,
        CASE WHEN id = 1 THEN p_table_name ELSE ” END AS table_name,
        CASE WHEN id = 1 THEN p_column_name ELSE ” END AS column_name,
        CASE WHEN id = 1 THEN last_updated ELSE ” END AS last_updated,
        CASE WHEN id = 1 THEN number_of_buckets_specified ELSE ” END AS ‘number_of_buckets_specified’ ,
        id AS buckets_specified_index,
        buckets_content
    FROM
    (
        SELECT * FROM cte,t_buckets
    )t;

END$$

DELIMITER ;

于是,第一个截图中的结果就转换为了如下的格式
这里刻意按照 4 个 buckets 生成的直方图,应该来说足够简单了,熟悉 MSSQL 直方图同学,应该一眼就可以看明白这个直方图的含义(测试数据量是 400,000)
以第一个 bucket 为例:[“2018-06-15 04:57:48.000000”, “2018-07-02 15:13:04.000000”, 0.25, 95311]

很明显,
1,”2018-06-15 04:57:48.000000″ 和 ”2018-07-02 15:13:04.000000″ 是类似于 sqlserver 中直方图中的下限值与上限值
2,0.25 小于 bucket 的值的比例(也就小于这个区间上限制值的比例)
3,95311 是这个区间的字段值不重复的行数。
到最后一个 bucket,采样率必然是 1,也就是 100%

MySQL 8.0 中统计信息直方图的尝试

需要注意的是,直方图的更新时间是标准时间(UTC value),而不是服务器当前时间。
MySQL 8.0 中的直方图基本上与 sqlserver 的直方图一致,都是基于单列的抽样预估,但是 MySQL 直方图中没有类似于 sqlserver 中的字段选择性,
不过这个字段选择性本身意义也不大,sqlserver 中对于复合索引,两个字段合计在一块统计,除非两个字段的同时分布的都很均匀,否则多字段索引的字段选择性参考意义不大。
这也是复合索引无法做到较为精确预估的原因。

存在的疑问?

写过一点 MySQL 统计信息的,不过是在 MySQL5.7 下面,还没有直方图的概念 https://www.linuxidc.com/Linux/2018-08/153704.htm
触发统计信息更新的变量还是 set global innodb_stats_on_metadata = 1; 但是经测试,统计信息的直方图并没有因此而更新。
innodb_stats_on_metadata 在 MySQL5.7 中影响到的是 MySQL 的索引上的统计信息,而这里纯粹是统计信息的直方图(MySQL 8.0 中直方图跟索引没有必然的关系)。
另外,这里经过反复测试发现,buckets 的数据量,与生成直方图的效率并没有非常明显的关系,如下截图,也并不清楚,buckets 数量跟取样百分比有什么关系。

MySQL 8.0 中统计信息直方图的尝试

又仔细看了一下参考链接的内容,发现这么一段话:

  1. Maintaining an index has a cost. If you have an index, every INSERT/UPDATE/DELETE causes the index to be updated. This is not free, and will have an impact on your performance. A histogram on the other hand is created once and never updated unless you explicitly ask for it. It will thus not hurt your INSERT/UPDATE/DELETE-performance.

  它本身是说明索引与直方图之间的关系的,提到直方图创建之后并不会自动更新,除非主动更新。

不得不吐槽的就是,如果我在某个字段上创建了一个索引,还需要顺便在创建一个统计信息直方图?并且这个直方图并不会随着数据的变化自动更新,还需要手动更新。
MySQL 8.0 中会不会把统计信息和索引关联起来,或者根据需要自动创建统计信息,如果统计信息做不到自动更新,基本上可以认为是残废的统计信息了。

关于生成直方图中时的资源的消耗

直方图的生成是一个比较消耗资源的过程的,如下是在反复测试创建直方图的过程中,zabbix 监控到的服务器的 CPU 使用情况,当然,这里仅仅观察了一下 CPU 使用率的问题。
因此,直方图再好,真要大规模应用的使用,还是要综合考量的,在什么时候执行更新,以及怎么去触发它的更新。

MySQL 8.0 中统计信息直方图的尝试

这里仅仅是粗浅尝试,难免有很多认识不足的地方。

一些有意思的东西

本文最后给出的参考链接中发现一些有意思的东西
MySQL 8.0 中一些有意思的预估算法,看来看去,跟 sqlserver 中的差别不大,都是类似大概这几种算法,算是没有办法的办法了。
对于两个谓词结合在一起时候的预估,或者是没有统计信息覆盖的预估,基本上可以认为是瞎蒙的,因此上文中也提到,多个谓词结合起来的���择性,没有什么意义。

————————————
AND      : P(A and B) = P(A) * P(B)
OR        : P(A or B)  = P(A) + P(B) – P(A and B)
=        : 1/10
<,>      : 1/3
BETWEEN  : 1/4
IN (list) : MIN(#items_in_list * SEL(=), 1/2)
IN subq  : [1]
NOT OP    : 1-SEL(OP)

正文完
星哥玩云-微信公众号
post-qrcode
 0
星锅
版权声明:本站原创文章,由 星锅 于2022-01-22发表,共计5282字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
【腾讯云】推广者专属福利,新客户无门槛领取总价值高达2860元代金券,每种代金券限量500张,先到先得。
阿里云-最新活动爆款每日限量供应
评论(没有评论)
验证码
【腾讯云】云服务器、云数据库、COS、CDN、短信等云产品特惠热卖中

星哥玩云

星哥玩云
星哥玩云
分享互联网知识
用户数
4
文章数
19352
评论数
4
阅读量
8018534
文章搜索
热门文章
星哥带你玩飞牛NAS-6:抖音视频同步工具,视频下载自动下载保存

星哥带你玩飞牛NAS-6:抖音视频同步工具,视频下载自动下载保存

星哥带你玩飞牛 NAS-6:抖音视频同步工具,视频下载自动下载保存 前言 各位玩 NAS 的朋友好,我是星哥!...
星哥带你玩飞牛NAS-3:安装飞牛NAS后的很有必要的操作

星哥带你玩飞牛NAS-3:安装飞牛NAS后的很有必要的操作

星哥带你玩飞牛 NAS-3:安装飞牛 NAS 后的很有必要的操作 前言 如果你已经有了飞牛 NAS 系统,之前...
我把用了20年的360安全卫士卸载了

我把用了20年的360安全卫士卸载了

我把用了 20 年的 360 安全卫士卸载了 是的,正如标题你看到的。 原因 偷摸安装自家的软件 莫名其妙安装...
再见zabbix!轻量级自建服务器监控神器在Linux 的完整部署指南

再见zabbix!轻量级自建服务器监控神器在Linux 的完整部署指南

再见 zabbix!轻量级自建服务器监控神器在 Linux 的完整部署指南 在日常运维中,服务器监控是绕不开的...
飞牛NAS中安装Navidrome音乐文件中文标签乱码问题解决、安装FntermX终端

飞牛NAS中安装Navidrome音乐文件中文标签乱码问题解决、安装FntermX终端

飞牛 NAS 中安装 Navidrome 音乐文件中文标签乱码问题解决、安装 FntermX 终端 问题背景 ...
阿里云CDN
阿里云CDN-提高用户访问的响应速度和成功率
随机文章
CSDN,你是老太太喝粥——无齿下流!

CSDN,你是老太太喝粥——无齿下流!

CSDN,你是老太太喝粥——无齿下流! 大家好,我是星哥,今天才思枯竭,不写技术文章了!来吐槽一下 CSDN。...
星哥带你玩飞牛NAS-6:抖音视频同步工具,视频下载自动下载保存

星哥带你玩飞牛NAS-6:抖音视频同步工具,视频下载自动下载保存

星哥带你玩飞牛 NAS-6:抖音视频同步工具,视频下载自动下载保存 前言 各位玩 NAS 的朋友好,我是星哥!...
亚马逊云崩完,微软云崩!当全球第二大云“摔了一跤”:Azure 宕机背后的配置风险与警示

亚马逊云崩完,微软云崩!当全球第二大云“摔了一跤”:Azure 宕机背后的配置风险与警示

亚马逊云崩完,微软云崩!当全球第二大云“摔了一跤”:Azure 宕机背后的配置风险与警示 首先来回顾一下 10...
把小米云笔记搬回家:飞牛 NAS 一键部署,小米云笔记自动同步到本地

把小米云笔记搬回家:飞牛 NAS 一键部署,小米云笔记自动同步到本地

把小米云笔记搬回家:飞牛 NAS 一键部署,小米云笔记自动同步到本地 大家好,我是星哥,今天教大家在飞牛 NA...
告别Notion焦虑!这款全平台开源加密笔记神器,让你的隐私真正“上锁”

告别Notion焦虑!这款全平台开源加密笔记神器,让你的隐私真正“上锁”

  告别 Notion 焦虑!这款全平台开源加密笔记神器,让你的隐私真正“上锁” 引言 在数字笔记工...

免费图片视频管理工具让灵感库告别混乱

一言一句话
-「
手气不错
星哥带你玩飞牛NAS-13:自动追番、订阅下载 + 刮削,动漫党彻底解放双手!

星哥带你玩飞牛NAS-13:自动追番、订阅下载 + 刮削,动漫党彻底解放双手!

星哥带你玩飞牛 NAS-13:自动追番、订阅下载 + 刮削,动漫党彻底解放双手! 作为动漫爱好者,你是否还在为...
三大开源投屏神器横评:QtScrcpy、scrcpy、escrcpy 谁才是跨平台控制 Android 的最优解?

三大开源投屏神器横评:QtScrcpy、scrcpy、escrcpy 谁才是跨平台控制 Android 的最优解?

  三大开源投屏神器横评:QtScrcpy、scrcpy、escrcpy 谁才是跨平台控制 Andr...
你的云服务器到底有多强?宝塔跑分告诉你

你的云服务器到底有多强?宝塔跑分告诉你

你的云服务器到底有多强?宝塔跑分告诉你 为什么要用宝塔跑分? 宝塔跑分其实就是对 CPU、内存、磁盘、IO 做...
星哥带你玩飞牛NAS-16:飞牛云NAS换桌面,fndesk图标管理神器上线!

星哥带你玩飞牛NAS-16:飞牛云NAS换桌面,fndesk图标管理神器上线!

  星哥带你玩飞牛 NAS-16:飞牛云 NAS 换桌面,fndesk 图标管理神器上线! 引言 哈...
手把手教你,购买云服务器并且安装宝塔面板

手把手教你,购买云服务器并且安装宝塔面板

手把手教你,购买云服务器并且安装宝塔面板 前言 大家好,我是星哥。星哥发现很多新手刚接触服务器时,都会被“选购...