什么叫覆盖索引?
解释一: 就是select的数据列只用从索引中就能够取得,不必从数据表中读取,换句话说查询列要被所使用的索引覆盖。
解释二: 索引是高效找到行的一个方法,当能通过检索索引就可以读取想要的数据,那就不需要再到数据表中读取行了。如果一个索引包含了(或覆盖了)满足查询语句中字段与条件的数据就叫做覆盖索引。
解释三:是非聚集组合索引的一种形式,它包括在查询里的Select、Join和Where子句用到的所有列(即建立索引的字段正好是覆盖查询语句[select子句]与查询条件[Where子句]中所涉及的字段,也即,索引包含了查询正在查找的所有数据)。
总之,不是所有类型的索引都可以成为覆盖索引。覆盖索引必须要存储索引的列,而哈希索引、空间索引和全文索引等都不存储索引列的值,所以MySQL只能使用B-Tree索引做覆盖索引
explain里type字段注解:
explain里extra字段注解:
using index :使用覆盖索引的时候就会出现
using where:在查找使用索引的情况下,需要回表去查询所需的数据
using index condition:查找使用了索引,但是需要回表查询数据
using index & using where:查找使用了索引,但是需要的数据都在索引列中能找到,所以不需要回表查询数据
有实验证明using index & using where要优于using index condition。
1.回表
上面讲过如果索引的列在select子句中就不需要回表,索引列也是表,如果索引中包括你需要的列,查询结果就找到了,如果没有你需要的列,索引列中有指针指向表记录的行位置,从表中查询列值。
2.索引篇
聚簇索引:每个InnoDB表具有一个特殊的索引称为聚集索引。如果您的表上定义有主键,该主键索引是聚集索引。如果你不定义为您的表的主键 时,MySQL取第一个唯一索引(unique)而且只含非空列(NOT NULL)作为主键,InnoDB使用它作为聚集索引。如果没有这样的列,InnoDB就自己产生一个这样的ID值,它有六个字节,而且是隐藏的,使其作为聚簇索引。
二级索引:又称辅助索引、非聚集索引(no-clustered index)。b+tree树结构,然而二级索引的叶子节点不保存记录中的所有列,其叶子节点保存的是<健值,(记录)地址>,非叶子节点存放的记录格式为<键值,主键值,地址>。而聚集索引叶子节点保存保存记录中的所有列,非叶子节点保存的是下一层节点地址。
做个测试吧:
建表:
CREATE TABLE `t_user` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `name` varchar(255) DEFAULT NULL, `age` tinyint(4) DEFAULT NULL, `create_time` datetime DEFAULT NULL, `update_time` datetime DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `name` (`name`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
生成测试数据:
DELIMITER ;; CREATE DEFINER=`root`@`%` PROCEDURE `proc_batch_insert`() BEGIN DECLARE pre_name BIGINT; DECLARE ageVal INT; DECLARE i INT; SET pre_name=187635267; SET ageVal=100; SET i=1; WHILE i < 1000000 DO INSERT INTO t_user(`name`,age,create_time,update_time) VALUES(CONCAT(pre_name,'@qq.com'),(ageVal+i)%30,NOW(),NOW()); SET pre_name=pre_name+100; SET i=i+1; END WHILE; END;; DELIMITER ;
id name age create_time update_time
1 187635267@qq.com 11 2019-06-13 01:53:36 2019-06-13 01:53:36
后面就用这一行记录做测试吧,先不加索引看看:
运行语句:
select name from t_user where name like '%187635267%';
这里扫了全表,无论是百分号的位置在哪边都会去扫全表。
那加个索引吧
create unique index `name` on `t_user` (`name`);
再运行同样的语句
Using where; Using index表示要查询的数据在索引列就能获取,所以并没有回表查询。
改下语句:
explain select name,age from t_user where name like '187635267%';
这边增加了age字段后,extra列显示Using index condition,因为age并不是索引 所以需要回表再查一遍age字段才行。
那么我加上复合索引呢?试试吧:
create index `index_name_age` on `t_user` (`name`,`age`);
再运行上面的语句:
又走回了覆盖索引,并且没有回表查询.因为name,age已经是复合索引了 在索引列就能获取到数据。上面也显示了用到了index_name_age这个索引.
如果不是建的复合索引呢,比如单独给age建一个索引:
create index `index_name_age` on `t_user` (`age`);
所以这里并没有用到age字段的索引,需要回表查询。
目前来说接触的大部分系统 后台都几乎是一张表的7,8成字段都要参与搜索,我总不可能每个字段都去建索引吧,目前能想到的时候把那种like查询的字段建上索引连同主键一起查出来,然后做二次查询,后面有没有更好的方法,需要以后实际中再考虑了。