「Mysql索引原理(十六)」维护索引和表-更新索引统计信息
MySQL的査询优化器会通过两个API来了解存储引擎的索引值的分布信息,以决定如何使用索引。第一个API是 records_in_range(),通过向存储引擎传入两个边界值获取在这个范围大概有多少条记录。对于某些存储引擎,该接口返回精确值,例如MyISAM;但对于另一些存储引擎则是一个估算值,例如 InnoDB。 第二个API是info(),该接口返回各种类型的数据,包括索引的基数(每个键值有多少条记录)。 如果存储引擎向优化器提供的扫描行数信息是不准确的数据,或者执行计划本身太复杂以致无法准确地获取各个阶段匹配的行数,那么优化器会使用索引统计信息来估算扫描行数。 MySQL优化器使用的是基于成本的模型,而衡量成本的主要指标就是一个查询需要扫描多少行。如果表没有统计信息,或者统计信息不准确,优化器就很有可能做出错误的决定。可以通过运行ANALYZE TABLE来重新生成统计信息解决这个问题。 每种存储引擎实现索引统计信息的方式不同,所以需要进行ANALYZE TABLE的频率也因不同的引擎而不同,每次运行的成本也不同:
- Memory引擎根本不存储索引统计信息。
- MyISAM将索引统计信息存储在磁盘中, ANALYZE TABLE需要进行一次全索引扫描来计算索引基数。在整个过程中需要锁表。
- 直到 My SQL5.5版本,InnoDB也不在磁盘存储索引统计信息,而是通过随机的索引访问进行评估并将其存储在内存中。 可以使用 SHOW INDEX FR0M命令来查看索引的基数( Cardinality)。例如
mysql> SHOW INDEX FROM people
image.png
这个命令输出了很多关于索引的信息,在MySQL手册中对上面每个字段的含义都有详细的解释。这里需要特别提及的是索引列的基数(Cardinality),其显示了存储引擎估算索引列有多少个不同的取值。在 MySQL5.0和更新的版本中,还可以通过
FORMATION_SCHEMA. STATISTICS表很方便地查询到这些信息。例如基于 INFORMATION_SCHEMA的表,可以编写一个查询给出当前选择性比较低的索引。需要注意的是,如果服务器上的库表非常多,则从这里获取元数据的速度可能会非常慢,而且会给 MySQL带来额外的压力。
InnodB的统计信息值得深入研究。 InnoDB引擎通过抽样的方式来计算统计信息,首先随机地读取少量的索引页面,然后以此为样本计算索引的统计信息。在老的 InnodB版本中,样本页面数是8,新版本的 InnoDB可以通过参数 innodb_stats_sample_pages来设置样本页的数量。设置更大的值,理论上来说可以帮助生成更准确的索引信息,特别是对于某些超大的数据表来说,但具体设置多大合适依赖于具体的环境。
InnoDB会在表首次打开,或者执行 ANALYZE TABLE,抑或表的大小发生非常大的变化(大小变化超过十六分之一或者新插入了20亿行都会触发)的时候计算索引的统计信息。
InnoDB在打开某些INF0RMATION_SCHEMA表,或者使用 SHOW TABLE STATUS和SHOW INDEX,抑或在MySQL客户端开启自动补全功能的时候都会触发索引统计信息的更新。如果服务器上有大量的数据,这可能就是个很严重的问题,尤其是当IO比较慢的时候。客户端或者监控程序触发索引信息采样更新时可能会导致大量的锁,并给服务器带来很多的额外压力,这会让用户因为启动时间漫长而沮丧。只要SHOW INDEX查看索引统计信息,就一定会触发统计信息的更新。可以关闭 innodb_stats_on_metadata参数来避免上面提到的问题。
如果想要更稳定的执行计划,并在系统重启后更快地生成这些统计信息,那么可以使用系统表来持久化这些索引统计信息。甚至还可以在不同的机器间迁移索引统计信息,这样新环境启动时就无须再收集这些数据。在官方的5.6版本都已经加入这个特,通过innodb_analyze_is_persistent参数控制。
一旦关闭索引统计信息的自动更新,那么就需要周期性地使用ANALYZE TABLE来手动更新。否则,索引统计信息就会永远不变。如果数据分布发生大的变,可能会出现一些很糟糕的执行计划。
- MySQL 教程
- MySQL 安装
- MySQL 管理与配置
- MySQL PHP 语法
- MySQL 连接
- MySQL 创建数据库
- MySQL 删除数据库
- MySQL 选择数据库
- MySQL 数据类型
- MySQL 创建数据表
- MySQL 删除数据表
- MySQL 插入数据
- MySQL 查询数据
- MySQL where 子句
- MySQL UPDATE 查询
- MySQL DELETE 语句
- MySQL LIKE 子句
- mysql order by
- Mysql Join的使用
- MySQL NULL 值处理
- MySQL 正则表达式
- MySQL 事务
- MySQL ALTER命令
- MySQL 索引
- MySQL 临时表
- MySQL 复制表
- 查看MySQL 元数据
- MySQL 序列 AUTO_INCREMENT
- MySQL 处理重复数据
- MySQL 及 SQL 注入
- MySQL 导出数据
- MySQL 导入数据
- MYSQL 函数大全
- MySQL Group By 实例讲解
- MySQL Max()函数实例讲解
- mysql count函数实例
- MYSQL UNION和UNION ALL实例
- MySQL IN 用法
- MySQL between and 实例讲解
- 如何交互可视化 Roam Research 局部笔记网络?
- Spark Kubernetes 的源码分析系列 - features
- Spark Kubernetes 的源码分析系列 - scheduler
- 简易Ramdisk 镜像制作(基于Centos7+)
- 在 K8S 部署一个 Spark History Server - 篇1
- R语言入门之非参数假设检验
- 在 K8S 部署一个 Spark History Server - 篇2
- UEFI/LEGACY 可启动ISO制作
- Kerberized HDFS with Kubernetes
- 经典 | Python实例小挑战—Part nine
- Mac CPU 相关
- 经典 | Python实例小挑战—Part ten
- 查看 Linux CPU 信息
- 方差分析(ANOVA)
- ps 究竟是 aux 还是 ef