首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >为什么要关注索引统计误差

为什么要关注索引统计误差

作者头像
田帅萌
发布于 2019-07-19 09:35:30
发布于 2019-07-19 09:35:30
49200
代码可运行
举报
文章被收录于专栏:「3306 Pai」社区「3306 Pai」社区
运行总次数:0
代码可运行

导读

由一个不可思议的索引统计信息误差案例引发的监控需求。

事情的起因是,我的朋友小明同学有一天突然发现有个SQL的执行计划出问题了。经过一番排查,居然发现是该表的辅助索引统计信息存在严重偏差。

我们知道,InnoDB表里每个辅助索引都会同时存储聚集索引列值,这就是所谓的 Index Extensions特性。那么,在统计索引信息时,包含聚集索引列的统计值就应该和聚集索引列的值几乎一样的才对,比如:(建议横屏观看)

代码语言:javascript
代码运行次数:0
运行
复制
[root@yejr.me]>select * from mysql.innodb_index_stats;
+------------+------------+------------+-------------+------------------+
| table_name | index_name | stat_value | sample_size | stat_description |
+------------+------------+------------+-------------+------------------+
...
| zst        | PRIMARY    |      40002 |          20 | id               |
...
| zst        | k1         |      40376 |          20 | uid,id           |
...
+------------+------------+------------+-------------+------------------+

可以看到k1索引的 (uid, id) 统计值(stat_value列)和主键索引是几乎差不多的。

这次小明遇到的问题,也是我这么多年来头一次遇到过,而且这还是在国内某知名公有云数据库上发生的,简直有点不太可思议。提交工单后,工程师给的答复也表示以前没遇到过,暂时不确定是什么原因引起的。

既然这种问题不能避免,那就自己主动加个监控吧,于是就有了本文。

解决方案

找出索引统计信息中,辅助索引统计信息和主键索引相差太大的情况,也就是辅助索引的基数和主键索引相差太大的现象,发出告警,并且手动执行 ANALYZE TABLE t 更新索引统计信息,一般就能解决问题了

如何监控

  1. 每个非唯一辅助索引都会包含主键列,正常情况下,包含主键列的那行统计信息和主键索引的统计信息相差不会太大。
  2. 唯一索引比较特殊,因为在 mysql.innodb_index_stats 表中,唯一索引列统计信息不会再包含主键列,但其基准值和主键列的基准值也不能相差太大。

假设有个表t3的索引统计数据如下(建议横屏观看)

代码语言:javascript
代码运行次数:0
运行
复制
[root@yejr.me] [mysql]>select database_name as db,
   table_name as tbl, index_name as idx, stat_name,
   stat_value, stat_description
    from innodb_index_stats where
    database_name = 'zhishutang' and table_name = 't3';
+------------+-----+---------+--------------+------------+-----------------------------------+
| db         | tbl | idx     | stat_name    | stat_value | stat_description                  |
+------------+-----+---------+--------------+------------+-----------------------------------+
| zhishutang | t3  | PRIMARY | n_diff_pfx01 |       1900 | id                                |
| zhishutang | t3  | PRIMARY | n_leaf_pages |          1 | Number of leaf pages in the index |
| zhishutang | t3  | PRIMARY | size         |          1 | Number of pages in the index      |
| zhishutang | t3  | name    | n_diff_pfx01 |          1 | name                              |
| zhishutang | t3  | name    | n_diff_pfx02 |         19 | name,id                           |
| zhishutang | t3  | name    | n_leaf_pages |          1 | Number of leaf pages in the index |
| zhishutang | t3  | name    | size         |          1 | Number of pages in the index      |
| zhishutang | t3  | nu      | n_diff_pfx01 |       1900 | nu                                |
| zhishutang | t3  | nu      | n_leaf_pages |          1 | Number of leaf pages in the index |
| zhishutang | t3  | nu      | size         |          1 | Number of pages in the index      |
+------------+-----+---------+--------------+------------+-----------------------------------+

以上面为例,希望得到的结果是

  1. 唯一索引nu的统计信息和主键索引统计信息一样,没问题。
  2. 辅助索引name的第二条(含主键列的那条)统计信息 (name, id) 和主键索引统计信息相差太远,属于异常,要能被发现。

实现该目的的SQL方法如下:(建议横屏观看)

代码语言:javascript
代码运行次数:0
运行
复制
set @statdb = 'yejr';
select
a.database_name ,
a.table_name ,
a.index_name ,
a.stat_value SK,
b.stat_value PK,
round((a.stat_value/b.stat_value)*100,2) stat_pct
from
(
select
b.database_name  ,
b.table_name  ,
b.index_name ,
b.stat_value
from
(
select database_name  ,
table_name  ,
index_name ,
max(stat_name) stat_name
from innodb_index_stats
where   database_name = @statdb
and stat_name not in ( 'size' ,'n_leaf_pages' )
group by
database_name  ,
table_name  ,
index_name
) a join innodb_index_stats b on a.database_name=b.database_name
and a.table_name=b.table_name
and a.index_name=b.index_name
and a.stat_name=b.stat_name
and b.index_name !='PRIMARY'
) a left join
(
select
b.database_name  ,
b.table_name  ,
b.index_name ,
b.stat_value
from
(
select database_name  ,
table_name  ,
index_name ,
max(stat_name) stat_name
from innodb_index_stats
where   database_name = @statdb
and stat_name not in ( 'size' ,'n_leaf_pages' )
group by
database_name  ,
table_name  ,
index_name
) a join innodb_index_stats b
on a.database_name=b.database_name
and a.table_name=b.table_name
and a.index_name=b.index_name
and a.stat_name=b.stat_name
and b.index_name ='PRIMARY'
) b
on a.database_name=b.database_name
and a.table_name=b.table_name
where b.stat_value is not null
and  a.stat_value >0
order by stat_pct;

+---------------+-------------------+--------------+--------+--------+----------+
| database_name | table_name        | index_name   | SK     | PK     | stat_pct |
+---------------+-------------------+--------------+--------+--------+----------+
| zhishutang    | t_json_vs_vchar   | c1vc         |  37326 |  39825 |    93.73 |
| zhishutang    | t_json_vs_vchar   | c2vc         |  37371 |  39825 |    93.84 |
| zhishutang    | t1                | name         | 299815 | 299842 |    99.99 |
| zhishutang    | t4                | c2           |      2 |      2 |   100.00 |
+---------------+-------------------+--------------+--------+--------+----------+

上面的SQL逻辑过于复杂,我是搞不定的,也是请知数堂SQL优化班郑松华老师帮忙给写的。

这个SQL脚本,我也已放在知数堂github库里“查看索引统计偏差”。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-07-17,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 3306pai 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
InnoDB的统计信息表
https://www.cnblogs.com/sunss/p/6110383.html
保持热爱奔赴山海
2019/09/17
8970
统计信息记录表|全方位认识 mysql 系统库
在上一期《数据库对象信息记录表|全方位认识 mysql 系统库》中,我们详细介绍了mysql系统库中的元数据记录表,本期我们将为大家带来系列第四篇《统计信息记录表|全方位认识 mysql 系统库》,下面请跟随我们一起开始 mysql 系统库的系统学习之旅吧。
老叶茶馆
2020/12/15
1.2K0
连接查询成本(2)---mysql进阶(四十二)
上篇文章说了连接查询的成本,主要由驱动表的扇出值和被驱动表的查询方法决定,而成本这些都是可以在%cost%表查看的,因为分为server和engine表,server不管理数据成本,里面包含连接管理,查询缓存,sql解码,sql优化,engine就是数据引擎成本,而distinct,union等特殊查询,会建立临时表,临时表看数据量可能建立磁盘或者内存,比如distinct会用unique索引建立临时表去重。
keying
2022/07/26
7960
第13期:表统计信息的计算
本篇介绍 MySQL 表如何计算统计信息。表统计信息是数据库基于成本的优化器最重要的参考信息;统计信息不准确,优化器可能给出不够优化的执行计划或者是错误的执行计划。
爱可生开源社区
2020/09/28
7530
MySQL统计信息相关表介绍
以前给大家介绍过MySQL中的统计信息,相信大家也都了解了。那么统计信息是存放在哪里呢?我们怎么去查看? 在MySQL中提供了两个表记录统计信息的相关内容,分别是 innodb_table_stats
沃趣科技
2018/03/26
2.3K0
MySQL统计信息相关表介绍
MySQL 统计信息简介
MySQL执行SQL会经过SQL解析和查询优化的过程,解析器将SQL分解成数据结构并传递到后续步骤,查询优化器发现执行SQL查询的最佳方案、生成执行计划。查询优化器决定SQL如何执行,依赖于数据库的统计信息,下面我们介绍MySQL 5.7中innodb统计信息的相关内容。
阿炳数记
2019/02/27
2.4K0
MySQL 统计信息简介
翻译|MySQL统计信息不准导致的性能问题
一个客户的性能优化案例: 没有修改数据库实例的任何配置参数以及业务代码没有变更的情况下,一条 sql 出现大幅性能下降。
用户1278550
2022/05/17
1.3K0
MySQL中的统计信息相关参数介绍
统计信息的作用 上周同事在客户现场遇到了由于统计信息的原因,导致应用数据迁移时间过慢,整个迁移差点失败。关键时刻同事发现测试环境与生产环境SQL语句执行计划不一致,立刻收集统计信息才保证迁移得以正常完成。 统计信息对于SQL的执行时间有重要的影响,统计信息的不准确会导致SQL的执行计划不准确,从而致使SQL执行时间变慢,Oracle DBA非常了解统计信息的收集规则,同样在MySQL中也有相关的参数去控制统计信息。 相关参数 innodb_stats_auto_recalc 控制innodb是否自动收集统
沃趣科技
2018/03/26
1.6K0
MySQL中的统计信息相关参数介绍
[MYSQL] mysql空间问题案例分享
某环境自上线以来, 空间使用越来越多. 总是扩空间也不是办法啊. 于是只能看能不能从数据库层面来释放一部分空间了.
大大刺猬
2025/02/20
2780
[MYSQL] mysql空间问题案例分享
应用示例荟萃|全方位认识 mysql 系统库
在上一期《日志记录等混杂表|全方位认识 mysql 系统库》中,我们详细介绍了mysql系统库中的日志记录表,本期我们将为大家带来系列第九篇《应用示例荟萃|全方位认识 mysql 系统库》,也是"全方位认识 mysql 系统库"的最后一篇,下面请跟随我们一起开始 mysql 系统库的系统学习之旅吧
老叶茶馆
2020/12/15
5440
show index from 及analyze table 详解
https://mp.weixin.qq.com/s/1MsyxhtG6Zk3Q9gIV2QVbA
保持热爱奔赴山海
2019/09/17
1.2K0
深入解析:从源码窥探MySQL优化器
作者 | 汤爱中,云和恩墨SQM开发者,Oracle/MySQL/DB2的SQL解析引擎、SQL审核与智能优化引擎的重要贡献者,产品广泛应用于金融、电信等行业客户中。
数据和云
2018/12/29
2.3K0
深入解析:从源码窥探MySQL优化器
为什么SHOW TABLE STATUS显示Rows少了40%
测试环境中,有一个表执行 SHOW TABLE STATUS 时看到的 rows 结果总是和真实数量相差了将近40%:
老叶茶馆
2024/03/12
2050
为什么SHOW TABLE STATUS显示Rows少了40%
MySQL5.7.25 下 报错提示innodb_table_stats 解决方法
最近在做灾备数据从库, 从库版本使用的是5.7.25, 主库版本是5.7.22. 配置完主从同步后,瞄了一眼从库的错误日志里面,突然蹦出一堆的下面这种:
保持热爱奔赴山海
2019/09/17
2.6K0
活久见,为什么SHOW TABLE STATUS总是不更新
前几天,QQ群里在讨论一个关于MySQL表统计信息迟迟不更新的问题。 这个问题我复现了,下面是详细过程:
老叶茶馆
2020/06/24
2.2K0
InnoDB 表空间可视化工具innodb_ruby
操作系统版本:CentOS Linux release 7.6.1810 (Core),默认的yum源安装后ruby的版本是2.0 ,而innodb_ruby需要2.2及以上版本,因此修改yum源,再安装指定高版本
俊才
2021/04/25
1.4K0
Christina问我:你都是如何设计索引的?
数据库系列更新到现在我想大家对所有的概念都已有个大概认识了,这周我在看评论的时候我发现有个网友的提问我觉得很有意思:帅丙如何设计一个索引?你们都是怎么设计索引的?怎么设计更高效?
敖丙
2021/01/08
8550
Christina问我:你都是如何设计索引的?
MYSQL 8 统计信息持久化 与 null
在任何数据库中统计信息是帮助数据库查询中走更适合的查询路径的基础,MYSQL 8 中持久化的统计信息怎么做,怎么能持久化后提高执行计划的稳定性。
AustinDatabases
2020/06/01
8290
【MySQL】MySQL的索引
索引是通过某种算法,构建出一个数据模型,用于快速找出在某个列中有一特定值的行,不使用索
陶然同学
2023/03/12
3.4K0
【MySQL】MySQL的索引
MySQL innodb_table_stats表不存在的解决方法
虽然重启之后 , 数据库会自动创建一个 ibdata1 文件 , 但是上述系统表也是 innodb 引擎 , 所以不能访问了 .
保持热爱奔赴山海
2019/09/18
1.3K0
相关推荐
InnoDB的统计信息表
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档