mysql高效索引之覆盖索引
概念
如果索引包含所有滿足查詢需要的數據的索引成為覆蓋索引(Covering Index),也就是平時所說的不需要回表操作
判斷標準
使用explain,可以通過輸出的extra列來判斷,對于一個索引覆蓋查詢,顯示為using index,MySQL查詢優化器在執行查詢前會決定是否有索引覆蓋查詢 注意 1、覆蓋索引也并不適用于任意的索引類型,索引必須存儲列的值 2、Hash 和full-text索引不存儲值,因此MySQL只能使用B-TREE 3、并且不同的存儲引擎實現覆蓋索引都是不同的 4、并不是所有的存儲引擎都支持它們 5、如果要使用覆蓋索引,一定要注意SELECT 列表值取出需要的列,不可以是SELECT *,因為如果將所有字段一起做索引會導致索引文件過大,查詢性能下降,不能為了利用覆蓋索引而這么做 ? InnoDB 1、覆蓋索引查詢時除了除了索引本身的包含的列,還可以使用其默認的聚集索引列 2、這跟INNOB的索引結構有關系,主索引是B+樹索引存儲,也即我們所說的數據行即索引,索引即數據 3、對于INNODB的輔助索引,它的葉子節點存儲的是索引值和指向主鍵索引的位置,然后需要通過主鍵在查詢表的字段值,所以輔助索引存儲了主鍵的值 4、覆蓋索引也可以用上INNODB 默認的聚集索引 5、innodb引擎的所有儲存了主鍵ID,事務ID,回滾指針,非主鍵ID,他的查詢就會是非主鍵ID也可覆蓋來取得主鍵ID 覆蓋索引是一種非常強大的工具,能大大提高查詢性能,只需要讀取索引而不用讀取數據有以下一些優點1、索引項通常比記錄要小,所以MySQL訪問更少的數據
2、索引都按值的大小順序存儲,相對于隨機訪問記錄,需要更少的I/O
3、大多數據引擎能更好的緩存索引,比如MyISAM只緩存索引
4、覆蓋索引對于InnoDB表尤其有用,因為InnoDB使用聚集索引組織數據,如果二級索引中包含查詢所需的數據,就不再需要在聚集索引中查找了
在sakila的inventory表中,有一個組合索引(store_id,film_id),對于只需要訪問這兩列的查 詢,MySQL就可以使用索引,如下 表結構
| 1 2 3 4 5 6 7 8 9 10 11 | 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 | |
?查詢語句
| 1 2 3 4 5 6 7 8 9 10 11 12 13 | 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的查 詢,如下
| 1 2 3 4 5 6 7 8 9 10 11 12 13 | 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,二是按索引順序掃描
利用索引進行排序操作是非??斓?#xff0c;而且可以利用同一索引同時進 行查找和排序操作。當索引的順序與ORDER BY中的列順序相同且所有的列是同一方向(全部升序或者全部降序)時,可以使用索引來排序,如果查詢是連接多個表,僅當ORDER BY中的所有列都是第一個表的列時才會使用索引,其它情況都會使用filesort
| 1 2 3 4 5 6 7 8 | 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
| 1 2 3 4 5 6 7 8 9 10 11 12 13 | 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
| 1 2 3 4 5 6 7 8 9 10 11 12 13 | 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
| 1 2 3 4 5 6 7 8 9 10 11 12 13 | 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
注:該算法是4.1之前采用的算法,它需要兩次訪問數據,尤其是第二次讀取操作會導致大量的隨機I/O操作。另一方面,內存開銷較小
2、 一次掃描算法(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”
- 作者:踏雪無痕
- 出處:http://www.cnblogs.com/chenpingzhao/
- 本文版權歸作者和博客園共有,歡迎轉載,如需聯系??pingzhao1990#163.com?
總結
以上是生活随笔為你收集整理的mysql高效索引之覆盖索引的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: SQL Server 和 MySql 语
- 下一篇: [MySQL] 索引与性能(3)- 覆盖