1 Create TABLE ‘t'( 2 'id' int(11) not null, 3 'a' int(11) default null, 4 'b' int(11) default null, 5 primary key ('id'), 6 key 'a' ('a'), 7 key 'b' ('b') 8 )ENGINE=InnoDB;
select * from t where a between 10000 and 20000; 优化器选择了索引a
rows字段表示预计扫描行数。
select * from t force index(a) where a between 10000 and 20000;
优化器的逻辑
在数据库里面,扫描行数是影响执行代价的因素之一。扫描的行数越少,意味着访问磁盘数据的次数越少,消耗的 CPU 资源越少。
扫描行数并不是唯一的判断标准,优化器还会结合是否使用临时表、是否排序等因素进行综合判断。普通索引还会考虑回表的代价。
扫描行数是怎么判断的?根据统计信息来估算记录数,这个统计信息就是索引的“区分度”。一个索引上不同的值越多,这个索引的区分度就越好。而一个索引上不同的值得个数,称为“基数”。
MySQL是怎样得到索引的基数的呢?采样统计
采样统计的时候,InnoDB 默认会选择 N 个数据页,统计这些页面上的不同值,得到一个平均值,然后乘以这个索引的页面数,就得到了这个索引的基数。
对于由于索引统计信息不准确导致的问题,可以用 analyze table 来解决。
analyze table t
索引选择异常和处理
1.采用force index强行选择一个索引
2.修改SQL语句
3.新建更合适的索引,或删掉误用的索引