1. 程式人生 > 其它 >索引優化實戰

索引優化實戰

技術標籤:SQLjavamysql索引sql

  • 1、 全值匹配
  • 2、 最佳左字首法則:如果索引多列,要遵守最左字首法則。指的是查詢從索引的最左錢磊開始且不跳過索引中的列
  • 3、 不在索引上做任何操作(計算,函式,型別轉換),會導致索引失效
  • 4、 儲存引擎不能使用索引中範圍條件右邊的列
  • 5、 儘量使用覆蓋索引(只訪問索引的查詢(索引列和查詢列一致)),減少select *
  • 6、 Mysql在使用不等於(!=或者<>)的時候無法使用索引會導致全表掃描
  • 7、 Is null 和is not null 也無法使用索引
  • 8、 Like以萬用字元開頭(’%abc…’)mysql索引會失效
  • 9、 字串不加單引號索引會失效
  • 10、 少用or,用它來連線時索引會失效

針對上面的十種情況,實戰操作一下。

建表語句:

CREATE TABLE `student` (
  `sid` int(11) NOT NULL AUTO_INCREMENT,
  `stuCode` varchar(255) NOT NULL COMMENT '學號',
  `stuName` varchar(255) NOT NULL COMMENT '姓名',
  `class` varchar(255) DEFAULT NULL COMMENT '班級',
  `hobby` varchar(255) DEFAULT NULL COMMENT '愛好'
, PRIMARY KEY (`sid`) ) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8; INSERT INTO `Student` (`sid`, `stuCode`, `stuName`, `class`, `hobby`) VALUES ('1', '10001', 'zhangsan', '1', '2'); INSERT INTO ` Student` (`sid`, `stuCode`, `stuName`, `class`, `hobby`) VALUES ('2', '10002', 'wangwu', '2', NULL)
; INSERT INTO `Student` (`sid`, `stuCode`, `stuName`, `class`, `hobby`) VALUES ('3', '10003', 'xiaohong', '2', '1'); INSERT INTO `Student` (`sid`, `stuCode`, `stuName`, `class`, `hobby`) VALUES ('4', '10004', 'zhaosi', '3', NULL);

建立聯合索引stuCodeNameClass

ALTER TABLE `Student` ADD INDEX stuCodeNameClass ( `stuCode`,`stuName`,`class` )

檢視索引

show INDEX from student

在這裡插入圖片描述

這裡就可以看到我們建立的聯合索引(主鍵會自動建立索引)

1、 全值匹配

explain select * from student where stuCode='10001' and stuName = 'zhangsan' and class = '2'

在這裡插入圖片描述
從結果中我可以看出我們確實走了stuCodeNameClass索引,從ref的三個const看,我們建立的聯合索引,三個欄位都用到了,這種匹配效率是最好的(注意一下此時的key_len是2302)

現在我們去掉class條件,看看會怎麼樣

explain select * from student where stuCode='10001' and stuName = 'zhangsan'

在這裡插入圖片描述

這個可以看出我們沒有走全部的欄位,雖然這種也走了索引,但是效率沒有全值匹配好

2、 最佳左字首法則:如果索引多列,要遵守最左字首法則。指的是查詢從索引的最左前列開始且不跳過索引中的列

針對上面那個查詢語句,我們去掉了class,依然走了索引,現在我們把stuName也去掉,看看效果怎樣

explain select * from student where stuCode='10001'

在這裡插入圖片描述
不難看出,只有stuCode依然會走索引。那現在我們去掉stuCode,只用stuName和class

explain select * from student where stuName = 'zhangsan' and class = '2'

在這裡插入圖片描述

Type為All,並沒有走索引,因為該語句違背了最佳左綴法則,查詢從最左前列開始。

現在我們用stuCode和class來查詢,看看效果如何

explain select * from student where stuCode='10001' and class = '2'

在這裡插入圖片描述

從結果中看,只用了stuCode一個欄位,違背不跳過索引中的列

3、 不在索引上做任何操作(計算,函式,型別轉換),會導致索引失效
當我們只使用stuCode作為條件時,會走索引,如下

explain select * from student where stuCode='10001'

在這裡插入圖片描述

如果我們在條件stuCode上使用left函式(從左擷取)會怎樣

explain select * from student where LEFT(stuCode,7) ='10001'

在這裡插入圖片描述

Type為All,沒有走索引。

4、 儲存引擎不能使用索引中範圍條件右邊的列(簡單點來說就是條件範圍後面的索引會失效)
現在我們在建一個teacher表

CREATE TABLE `teacher` (
  `tid` int(11) NOT NULL,
  `number` int(11) DEFAULT NULL,
  `tCode` varchar(255) DEFAULT NULL,
  `tName` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`tid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `teacher` (`tid`, `number`, `tCode`, `tName`) VALUES ('1', '1', '20001', 'wang');
INSERT INTO `teacher` (`tid`, `number`, `tCode`, `tName`) VALUES ('2', '2', '20001', 'yang');

建立索引numCode

ALTER TABLE `teacher` ADD INDEX numCode ( `number`,`tCode`)

按索引查詢一下teacher

explain select * from teacher where number =1 and tCode = '20001'

在這裡插入圖片描述
正常走兩個索引,注意key_len是773,現在稍微改一下查詢語句

explain select * from teacher where number >1 and tCode = '20001'

在這裡插入圖片描述
Type是range我們從key可以看出我們還是走了索引,但是注意key_len可知我們只走了number索引,後面的tCode沒有使用。

**5、 儘量使用覆蓋索引(只訪問索引的查詢(索引列和查詢列一致)),減少select ***

現在還是使用student表

explain select * from student where stuCode = '10001' and stuName='zhangsan' and class = '1'

在這裡插入圖片描述

現在修改一下查詢語法

explain select stuCode,stuName,class from student where stuCode = '10001' and stuName='zhangsan' and class = '1'

在這裡插入圖片描述
跟上面的區別在於Extra中有一個Using index,這表示我們掃描了索引就可以獲得結果,不用再去掃描表,效果好

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

explain select * from student where stuCode != '10001'

在這裡插入圖片描述
7、 is null和is not null 也無法使用索引

explain select * from student where stuCode is not null

在這裡插入圖片描述
8、 like以萬用字元開頭(’%abc…’)mysql索引會失效
建立user表

CREATE TABLE `user` (
  `uid` int(11) NOT NULL,
  `uname` varchar(255) DEFAULT NULL,
  `uage` int(11) DEFAULT NULL,
  `usex` int(11) DEFAULT NULL,
  PRIMARY KEY (`uid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `user` (`uid`, `uname`, `uage`, `usex`) VALUES ('1', '1abc1', '1', NULL);
INSERT INTO `user` (`uid`, `uname`, `uage`, `usex`) VALUES ('2', '2abc2', '2', NULL);
INSERT INTO `user` (`uid`, `uname`, `uage`, `usex`) VALUES ('3', '3abc3', '3', NULL);

建立索引

ALTER TABLE `user` ADD INDEX nameAge ( `uname`,`uage`)

嘗試使用索引查詢

explain select * from user where uname like '%abc%'

在這裡插入圖片描述
但是隻有右邊有%的時候,是可以使用索引的

explain select * from user where uname like 'abc%'

在這裡插入圖片描述
但是有大部分需求是要求前後模糊查詢的,這個時候有什麼解決辦法呢,這個其實可以跟第五條結合

explain select uid,uname,uage from user where uname like '%abc%'

在這裡插入圖片描述
9、 字串不加單引號索引會失效
使用student表

explain select * from student where stuCode = 10001

在這裡插入圖片描述
10、 少用or,用它來連線時索引會失效

explain select * from student where stuCode = '10001' or stuName = 'zhangsan'

在這裡插入圖片描述