什么叫覆蓋索引?
解釋一: 就是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查詢的字段建上索引連同主鍵一起查出來,然后做二次查詢,后面有沒有更好的方法,需要以后實際中再考慮了。
