如果索引包含所有满足查询需要的数据,则该索引称为覆盖索引(Covering Index),也就是平时所说的不需要回表操作。 判断标准使用explain,可以通过输出的extra列来判断,对于一个索引覆盖查询,显示为using index,MySQL查询优化器在执行查询前会决定是否有索引覆盖查询 注意InnoDB
覆盖索引是一种非常强大的工具,能大大提高查询性能,只需要读取索引而不用读取数据有以下一些优点
在sakila的inventory表中,有一个组合索引(store_id,film_id),对于只需要访问这两列的查 询,MySQL就可以使用索引,如下 表结构 CREATE TABLE `inventory` (`inventory_id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT, `film_id` smallint(5) unsigned NOT NULL, `store_id` tinyint(3) unsigned NOT NULL, `last_update` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`inventory_id`), KEY `idx_fk_film_id` (`film_id`), KEY `idx_store_id_film_id` (`store_id`,`film_id`), CONSTRAINT `fk_inventory_film` FOREIGN KEY (`film_id`) REFERENCES `film` (`film_id`) ON UPDATE CASCADE, CONSTRAINT `fk_inventory_store` FOREIGN KEY (`store_id`) REFERENCES `store` (`store_id`) ON UPDATE CASCADE ) ENGINE=InnoDB AUTO_INCREMENT=4582 DEFAULT CHARSET=utf8 | 查询语句 mysql> EXPLAIN SELECT store_id, film_id FROM sakila.inventory\G*************************** 1. row *************************** id: 1 select_type: SIMPLE table: inventory type: index possible_keys: NULL key: idx_store_id_film_id key_len: 3 ref: NULL rows: 4581 Extra: Using index 1 row in set (0.03 sec) 在大多数引擎中,只有当查询语句所访问的列是索引的一部分时,索引才会覆盖。但是,InnoDB不限于此,InnoDB的二级索引在叶子节点中存储了 primary key的值。 因此,sakila.actor表使用InnoDB,而且对于是last_name上有索引,所以,索引能覆盖那些访问actor_id的查 询,如下 mysql> EXPLAIN SELECT actor_id, last_name FROM sakila.actor WHERE last_name = 'HOPPER'\G*************************** 1. row *************************** id: 1 select_type: SIMPLE table: actor type: ref possible_keys: idx_actor_last_name key: idx_actor_last_name key_len: 137 ref: const rows: 2 Extra: Using where; Using index 1 row in set (0.00 sec) 使用索引进行排序 MySQL中,有两种方式生成有序结果集:一是使用filesort,二是按索引顺序扫描 利用索引进行排序操作是非常快的,而且可以利用同一索引同时进 行查找和排序操作。当索引的顺序与ORDER BY中的列顺序相同且所有的列是同一方向(全部升序或者全部降序)时,可以使用索引来排序,如果查询是连接多个表,仅当ORDER BY中的所有列都是第一个表的列时才会使用索引,其它情况都会使用filesort CREATE TABLE `actor` (`actor_id` int(10) unsigned NOT NULL AUTO_INCREMENT, `name` varchar(16) NOT NULL DEFAULT '', `password` varchar(16) NOT NULL DEFAULT '', PRIMARY KEY (`actor_id`), KEY `name` (`name`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 ; insert into actor(name,password) values ('cat01','1234567'),('cat02','1234567'),('ddddd','1234567'),('aaaaa','1234567'); 1、explain select actor_id from actor order by actor_id \G mysql> explain select actor_id from actor order by actor_id \G*************************** 1. row *************************** id: 1 select_type: SIMPLE table: actor type: index possible_keys: NULL key: PRIMARY key_len: 4 ref: NULL rows: 4 Extra: Using index 1 row in set (0.00 sec) 2、explain select actor_id from actor order by password \G mysql> explain select actor_id from actor order by password \G*************************** 1. row *************************** id: 1 select_type: SIMPLE table: actor type: ALL possible_keys: NULL key: NULL key_len: NULL ref: NULL rows: 4 Extra: Using filesort 1 row in set (0.00 sec) 3、explain select actor_id from actor order by name \G mysql> explain select actor_id from actor order by name \G*************************** 1. row *************************** id: 1 select_type: SIMPLE table: actor type: index possible_keys: NULL key: name key_len: 50 ref: NULL rows: 4 Extra: Using index 1 row in set (0.00 sec) 当MySQL不能使用索引进行排序时,就会利用自己的排序算法(快速排序算法)在内存(sort buffer)中对数据进行排序,如果内存装载不下,它会将磁盘上的数据进行分块,再对各个数据块进行排序,然后将各个块合并成有序的结果集(实际上就是外排序) 对于filesort,MySQL有两种排序算法 1、两遍扫描算法(Two passes) 实现方式是先将需要排序的字段和可以直接定位到相关行数据的指针信息取出,然后在设定的内存(通过参数sort_buffer_size设定)中进行排序,完成排序之后再次通过行指针信息取出所需的Columns
2、 一次扫描算法(single pass) 该算法一次性将所需的Columns全部取出,在内存中排序后直接将结果输出
当对连接操作进行排序时,如果ORDER BY仅仅引用第一个表的列,MySQL对该表进行filesort操作,然后进行连接处理,此时,EXPLAIN输出“Using filesort”;否则,MySQL必须将查询的结果集生成一个临时表,在连接完成之后进行filesort操作,此时,EXPLAIN输出 “Using temporary;Using filesort” |
|免责声明|本站介绍|工控课堂
( 沪ICP备14007696号-3 )|网站地图
GMT+8, 2019-11-29 20:22 , Processed in 0.047055 second(s), 41 queries .
Powered by Discuz! X3.4
© 2001-2017 Comsenz Inc.