使用覆蓋索引優化like查詢


 

 

什么叫覆蓋索引?
解釋一: 就是select的數據列只用從索引中就能夠取得,不必從數據表中讀取,換句話說查詢列要被所使用的索引覆蓋。

解釋二: 索引是高效找到行的一個方法,當能通過檢索索引就可以讀取想要的數據,那就不需要再到數據表中讀取行了。如果一個索引包含了(或覆蓋了)滿足查詢語句中字段與條件的數據就叫做覆蓋索引。

解釋三:是非聚集組合索引的一種形式,它包括在查詢里的Select、Join和Where子句用到的所有列(即建立索引的字段正好是覆蓋查詢語句[select子句]與查詢條件[Where子句]中所涉及的字段,也即,索引包含了查詢正在查找的所有數據)。

總之,不是所有類型的索引都可以成為覆蓋索引。覆蓋索引必須要存儲索引的列,而哈希索引、空間索引和全文索引等都不存儲索引列的值,所以MySQL只能使用B-Tree索引做覆蓋索引

explain里type字段注解:

system
const的特例,僅返回一條數據的時候。
const 查找主鍵索引,返回的數據至多一條(0或者1條)。 屬於精確查找
eq_ref 查找唯一性索引,返回的數據至多一條。屬於精確查找 ref 查找非唯一性索引,返回匹配某一條件的多條數據。屬於精確查找、數據返回可能是多條
range 查找某個索引的部分索引,一般在where子句中使用 < 、>、in、between等關鍵詞。只檢索給定范圍的行,屬於范圍查找
index 查找所有的索引樹,比ALL要快的多,因為索引文件要比數據文件小的多。
ALL 不使用任何索引,進行全表掃描,性能最差。

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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM