MySql 索引優化原則

索引優化有很作最佳實踐原則,下面對常用原則進行分析。

MySql索引底層數據結構和算法:https://blog.csdn.net/yhl_jxy/article/details/88392411

MySql explan執行計劃詳解:https://blog.csdn.net/yhl_jxy/article/details/88570154

優化原則實例sql準備。

CREATE TABLE `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_name` varchar(24) NOT NULL DEFAULT '' COMMENT '用戶姓名',
  `user_age` int(11) NOT NULL DEFAULT 0 COMMENT '用戶年齡',
  `user_level` varchar(20) NOT NULL DEFAULT '' COMMENT '用戶等級',
  `register_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '註冊時間',
  PRIMARY KEY (`id`),
  KEY `idx_userName_userAge_userLevel` (`user_name`,`user_age`,`user_level`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用戶表';

INSERT INTO user(user_name, user_age, user_level, register_time)
VALUES('ZhangSan', 30, 'A', NOW()), ('LiSi', 31, 'B', NOW()), ('WangWu', 31, 'C', NOW());

1、全值匹配

按索引字段順序匹配使用。

mysql> explain select * from user where user_name = 'ZhangSan';

通過explain分析,type爲ref,使用索引,效率高。key_len爲74,根據key_len計算規則,如果字段類型爲varchar(n),

並且是utf-8編碼格式,則key_len=3n+2,where後使用了user_name,則key_len=3*24+2=74,證明索引用到了聯合索引的

第一個字段user_name,從ref也可以看到一個const。

使用聯合索引兩個字段時:

mysql> explain select * from user where user_name = 'ZhangSan' and user_age = 30;

使用聯合索引三個字段時:

mysql> explain select * from user where user_name = 'ZhangSan'and user_age = 30 and user_level = 'A';

2、最佳左前綴法則

如果建的是聯合索引,要遵循最左前綴法則。

要想使用索引,where後面的條件需要從索引的最左前列開始並且不跳過索引中的列使用。

mysql> explain select * from user where user_name = 'ZhangSan'and user_age = 30 and user_level = 'A';

按照索引字段順序使用,三個字段都使用了索引。

mysql> explain select * from user where user_age = 30 and user_level = 'A';

直接跳過user_name使用索引字段,索引無效,未使用到索引。

mysql> explain select * from user where user_age = 30 and user_level = 'A' and user_name = 'ZhangSan';

where後面查詢條件順序是user_age、user_level、user_name與我們建的索引順序user_name、user_age、user_level

不一致,爲什麼還是使用了索引,這是因爲MySql底層優化器給咱們做了優化。但是,咱們最好還是按順序使用索引。

3、不要在索引列上做任何操作,比如計算、使用函數、自動或手動進行類型轉換,

會導致索引失效,從而使查詢轉向全表掃描。

mysql> explain select * from user where user_name = 'ZhangSan';

where條件直接使用索引字段user_name用到了索引。

mysql> explain select * from user where right(user_name, 3) = 'San';

 

where條件使用計算後的索引字段user_name,沒有使用索引,索引失效。

4、存儲引擎不能使用範圍條件右邊的索引列。

mysql> explain select * from user where user_name = 'ZhangSan' and user_age = 30 and user_level = 'A';

三個列都使用“=”號,順序使用三個字段,三個字段都使用了索引。

mysql> explain select * from user where user_name = 'ZhangSan' and user_age > 30 and user_level = 'A';

將user_age修改爲">"之後,Extra爲Using index condition,表明索引沒有被完全使用,

並且key_len由140降爲78,說明最後一個字段user_level沒有使用索引。

即範圍之後索引全無效。

但是如果我們把“>”變爲">="呢?

mysql> explain select * from user where user_name = 'ZhangSan' and user_age >= 30 and user_level = 'A';

加上等號後,key_len變爲了140,但是Using index condition確又表明索引沒有被完全使用,

只能說明在滿足user_age爲“=”號條件時全部索引使用,否則,範圍之後的索引失效。

5、儘量使用覆蓋索引(只訪問索引的查詢(索引列包含查詢列)),減少select *語句。

mysql> explain select * from user where user_name = 'ZhangSan' and user_age  = 30 and user_level = 'A';

Extra顯示null,表示查詢的列未被索引列覆蓋,並且where篩選條件是索引的前導列,說明用到了索引,

但是部分字段未被索引列覆蓋,必須通過“回表”來實現,所以不是純粹地用到了索引,也不是完全沒用到索引。

mysql> explain select user_name, user_age from user where user_name = 'ZhangSan' and user_age  = 30 and user_level = 'A';

將*換成索引列,查詢時使用了索引,用索引列覆蓋查詢的*, 叫做覆蓋索引。

6、mysql在使用不等於(!=或者<>)的時候無法使用索引會導致全表掃描。

mysql> explain select user_name, user_age from user where user_name = 'ZhangSan';

mysql> explain select user_name, user_age from user where  user_name != 'ZhangSan';

Extra顯示Using whre Using index,表示查詢的列被索引列覆蓋,但是where後面條件未使用索引,

說明無法直接通過索引查找查詢到符合條件的數據。 

7、is null,is not null 也無法使用索引。

mysql> explain select * from user where user_name = 'ZhangSan';

使用了索引。

mysql> explain select * from user where user_name is not null;

未使用索引。

8、like以通配符開頭(like '%aaa')mysql索引失效會變成全表掃描操作。

mysql> explain select * from user where user_name like '%San';

%開頭,未使用索引。

mysql> explain select * from user where user_name like 'Zhang%';

%結尾,使用了索引。

mysql> explain select * from user where user_name like '%Zhang%';

%aaa%前後都使用%號,也未使用索引。

like使用總結:aaa%可以使用索引,但是%aaa或%aaa%相當於範圍查詢,

無法使用索引,以及在之後的索引列也會索引失效。 

總結

關於索引優化原則,可以做如下總結。

全值匹配心上人(這是基本原則),最左前綴要遵行(聯合索引一般都圍繞最左前綴優化);

帶頭大哥活纔行(聯合索引從最左邊字段開始使用),中間兄弟規矩行(不能跳過中間的字段,跳過後索引無效);

索引列上少計算(索引列上儘量不要進行計算)範圍之後全完蛋(where後面使用範圍查詢的之後的索引無效);

like百分最右寫(%號寫最右邊,寫左邊會導致索引失效)覆蓋索引別寫星(儘量避免select*這樣的語句,能寫索引列最好);

空值不等還有or,索引失效最無情(is null,is not null,!=,<>,or會導致索引無效);

關於索引優化原則,不同的sql版本會有不同,並且需要結合explain的各項參數分析,需要不斷體會,

explain博大精深。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章