索引優化有很作最佳實踐原則,下面對常用原則進行分析。
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博大精深。