mysql高效索引之覆盖索引

概念php

若是索引包含全部知足查询须要的数据的索引成为覆盖索引(Covering Index),也就是平时所说的不须要回表操做mysql

判断标准算法

使用explain,能够经过输出的extra列来判断,对于一个索引覆盖查询,显示为using index,MySQL查询优化器在执行查询前会决定是否有索引覆盖查询
 
注意
一、覆盖索引也并不适用于任意的索引类型,索引必须存储列的值
二、Hash 和full-text索引不存储值,所以MySQL只能使用B-TREE
三、而且不一样的存储引擎实现覆盖索引都是不一样的
四、并非全部的存储引擎都支持它们
五、若是要使用覆盖索引,必定要注意SELECT 列表值取出须要的列,不能够是SELECT *,由于若是将全部字段一块儿作索引会致使索引文件过大,查询性能降低,不能为了利用覆盖索引而这么作
 
InnoDB
一、覆盖索引查询时除了除了索引自己的包含的列,还可使用其默认的汇集索引列
二、这跟INNOB的索引结构有关系,主索引是B+树索引存储,也即咱们所说的数据行即索引,索引即数据
三、对于INNODB的辅助索引,它的叶子节点存储的是索引值和指向主键索引的位置,而后须要经过主键在查询表的字段值,因此辅助索引存储了主键的值
四、覆盖索引也能够用上INNODB 默认的汇集索引
五、innodb引擎的全部储存了主键ID,事务ID,回滚指针,非主键ID,他的查询就会是非主键ID也可覆盖来取得主键ID
 
覆盖索引是一种很是强大的工具,能大大提升查询性能,只须要读取索引而不用读取数据有如下一些优势
一、索引项一般比记录要小,因此MySQL访问更少的数据
二、索引都按值的大小顺序存储,相对于随机访问记录,须要更少的I/O
三、大多数据引擎能更好的缓存索引,好比MyISAM只缓存索引
四、覆盖索引对于InnoDB表尤为有用,由于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 |

 查询语句sql

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');

一、 explain select actor_id from actor order by actor_id \Gspa

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)

 二、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)

 三、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有两种排序算法

一、两遍扫描算法(Two passes)

实现方式是先将需要排序的字段和能够直接定位到相关行数据的指针信息取出,而后在设定的内存(经过参数sort_buffer_size设定)中进行排序,完成排序以后再次经过行指针信息取出所需的Columns
注:该算法是4.1以前采用的算法,它须要两次访问数据,尤为是第二次读取操做会致使大量的随机I/O操做。另外一方面,内存开销较小


二、 一次扫描算法(single pass)

该算法一次性将所需的Columns所有取出,在内存中排序后直接将结果输出注: 从 MySQL 4.1 版本开始使用该算法。它减小了I/O的次数,效率较高,可是内存开销也较大。若是咱们将并不须要的Columns也取出来,就会极大地浪费排序过程所须要 的内存。在 MySQL 4.1 以后的版本中,能够经过设置 max_length_for_sort_data 参数来控制 MySQL 选择第一种排序算法仍是第二种。当取出的全部大字段总大小大于 max_length_for_sort_data 的设置时,MySQL 就会选择使用第一种排序算法,反之,则会选择第二种。为了尽量地提升排序性能,咱们天然更但愿使用第二种排序算法,因此在 Query 中仅仅取出须要的 Columns 是很是有必要的。当对链接操做进行排序时,若是ORDER BY仅仅引用第一个表的列,MySQL对该表进行filesort操做,而后进行链接处理,此时,EXPLAIN输出“Using filesort”;不然,MySQL必须将查询的结果集生成一个临时表,在链接完成以后进行filesort操做,此时,EXPLAIN输出 “Using temporary;Using filesort”

相关文章
相关标签/搜索