可以看到数据都放在主键索引上,如果从逻辑上说,所有的InnoDB表上的查询,都至少用了一个索
引,所以现在我问你一个问题,如果你执行select from t where id>0,你觉得这个语句有用上索引吗?
我们看上面这个语句的explain的输出结果显示的是PRIMARY。其实从数据上你是知道的,这个语句一
定是做了全面扫描。但是优化器认为,这个语句的执行过程中,需要根据主键索引,定位到第1个满足
ID>0的值,也算用到了索引。
所以即使explain的结果里写的KEY不是NULL,实际上也可能是全表扫描的,因此InnoDB里面只有一
种情况叫做没有使用索引,那就是从主键索引的最左边的叶节点开始,向右扫描整个索引树。
也就是说,没有使用索引并不是一个准确的描述。
你可以用全表扫描来表示一个查询遍历了整个主键索引树;
也可以用全索引扫描,来说明像select a from t;这样的查询,他扫描了整个普通索引树;
而select * from t where id=2这样的语句,才是我们平时说的使用了索引。他表示的意思是,我们使用
了索引的快速搜索功能,并且有效的减少了扫描行数。
索引的过滤性要足够好
根据以上解剖,我们知道全索引扫描会让查询变慢,接下来就要来谈谈索引的过滤性。
假设你现在维护了一个表,这个表记录了中国14亿人的基本信息,现在要查出所有年龄在10~15岁之
间的姓名和基本信息,那么你的语句会这么写,select * from t_people where age between 10 and
15。
你一看这个语句一定要在age字段上开始建立索引了,否则就是个全面扫描,但是你会发现,在你建立
索引以后,这个语句还是执行慢,因为满足这个条件的数据可能有超过1亿行。
我们来看看建立索引以后,这个表的组织结构图:
那么过滤性好了,是不是表示查询的扫描行数就一定少呢?
我们再来看一个例子:
如果你的执行语句是 select * from t_people where name='张三' and age=8
t_people表上有一个索引是姓名和年龄的联合索引,那这个联合索引的过滤性应该不错,可以在联合
索引上快速找到第1个姓名是张三,并且年龄是8的小朋友,当然这样的小朋友应该不多,因此向右扫
描的行数很少,查询效率就很高。
但是查询的过滤性和索引的过滤性可不一定是一样的,如果现在你的需求是查出所有名字的第1个字是
张,并且年龄是8岁的所有小朋友,你的语句会怎么写呢?
你的语句要怎么写?
很显然你会这么写:select * from t_people where name like '张%' and age=8;
在MySQL5.5和之前的版本中,这个语句的执行流程是这样的: