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」

相關文章
相關標籤/搜索