10 | MySQL为什么有时候会选错索引?

mysql的表支持多索引,但是如果没有指定使用的索引,将由mysql确定使用哪个索引。

执行的很快的语句,由于MySQL选错了索引,导致执行速度变得很慢?

CREATE TABLE `t` (
 `id` int(11) NOT NULL,
 `a` int(11) DEFAULT NULL,
 `b` int(11) DEFAULT NULL,
 PRIMARY KEY (`id`),
 KEY `a` (`a`),
 KEY `b` (`b`)
)
select * from t where a between 10000 and 20000;

正常执行查询,能够使用索引 a,但是按照以下顺序执行,执行查询就不会使用索引,采用全表查询

优化器:选择索引是优化器的工作

选择索引是为了用最小的代价执行语句,扫描的行数是一个指标,扫描的行数越少,访问磁盘的次数也就越少,消耗的cpu也就越少。除此之外,是否使用临时表,是否排序也会作为索引选择的指标。

扫描行数是怎么判断的?

MySql执行之前并不知道满足条件的记录有多少条,只能根据统计信息估算记录数;统计信息就是索引的区分度,索引上不同值越多,区分度越好,索引的不同值称为基数(cardinality),基数越大,索引的区分度越好

 MySql怎么得到索引的基数?

 mysql采用采样统计,因为如果一行一行统计虽然准确,但是代价太大。

采样统计的时候,InnoDB默认选择N个数据页,统计页面上的不同值,得到一个平均值,然后乘以这个索引的页面数,得到索引基数。

数据不断变化,索引统计信息也不会固定不变,变更数据行数超过1/M的时候,自动触发索引统计。

MySql有两种索引统计的方式,可以设置innodb_stats_persistent值选择:

设置为 on 的时候,表示统计信息会持久化存储。这时,默认的 N 是 20,M 是 10。
设置为 off 的时候,表示统计信息只存储在内存中。这时,默认的 N 是 8,M 是 16。
为什么Mysql放着扫描行数少的不用,而用扫描行数多的执行计划?
因为每次查询要回表查询其他字段, 优化器认为直接扫描主键索引更快, 当然,从执 行时间看来,这个选择并不是最优的
统计信息不对,使用 analyze table t命令修正,重新统计索引信息; 实践中,如果你发现 explain
的结果预估的 rows 值跟实际情况差距比较大,可以采用这个方法来处理。
索引选择异常和处理:
1、采用 force index() 强制使用一个索引 MySQL 会根据词 法解析的结果分析出可能可以使用的索引作为候选项,然后在候选列表中依次判断每个索引需要 扫描多少行。如果 force index 指定的索引在候选索引列表中,就直接选择这个索引,不再评估 其他索引的执行代价。
2、考虑修改语句,引导mysql使用我们的期望结果。比如使用某索引扫描行数比较多,但是用他进行排序,优化器也会使用它,那么可以考虑将期望的索引也加入排序,根据场景处理
3、新建更合适的索引,提供给优化器,或者删掉无用索引
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值