Mysql的索引優(yōu)化原則詳解
- 創(chuàng)建數(shù)據(jù)庫(kù)、表,插入數(shù)據(jù)
create database idx_optimize character set 'utf8';
CREATE TABLE users(
id INT PRIMARY KEY AUTO_INCREMENT,
user_name VARCHAR(20) NOT NULL COMMENT '姓名',
user_age INT NOT NULL DEFAULT 0 COMMENT '年齡',
user_level VARCHAR(20) NOT NULL COMMENT '用戶等級(jí)',
reg_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '注冊(cè)時(shí)間'
);
INSERT INTO users(user_name,user_age,user_level,reg_time)
VALUES('tom',17,'A',NOW()),('jack',18,'B',NOW()),('lucy',18,'C',NOW());- 創(chuàng)建聯(lián)合索引
ALTER TABLE users ADD INDEX idx_nal (user_name,user_age,user_level) USING BTREE;
2.優(yōu)化原則詳解
1)最佳左前綴法則
最佳左前綴法則: 如果創(chuàng)建的是聯(lián)合索引,就必須遵守這個(gè)法則,當(dāng)使用聯(lián)合索引時(shí),where后面條件需要從索引的最左前開始使用。
- 場(chǎng)景1: 按照索引字段順序使用,三個(gè)字段都使用了索引,沒有問題
EXPLAIN SELECT * FROM users WHERE user_name = 'tom' AND user_age = 17 AND user_level = 'A';

- 場(chǎng)景2: 直接跳過user_name使用索引字段,索引無效,未使用到索引。
EXPLAIN SELECT * FROM users WHERE user_age = 17 AND user_level = 'A';

- 場(chǎng)景3: 不按照創(chuàng)建聯(lián)合索引的順序,使用索引
EXPLAIN SELECT * FROM users WHERE user_age = 17 AND user_name = 'tom' AND user_level = 'A';

where后面查詢條件順序是 user_age、user_level、user_name與我們創(chuàng)建的索引順序user_name、user_age、user_level不一致,為什么還是使用了索引,原因是因?yàn)镸ySql底層優(yōu)化器對(duì)其進(jìn)行了優(yōu)化。
- 最佳左前綴底層原理
- MySQL創(chuàng)建聯(lián)合索引的時(shí)候要遵守一個(gè)規(guī)則: 首先會(huì)對(duì)聯(lián)合索引最左邊的字段進(jìn)行排序,再在第一個(gè)字段的基礎(chǔ)之上對(duì)第二個(gè)字段進(jìn)行排序。

所以: 最佳左前綴原則其實(shí)是和B+樹的結(jié)構(gòu)有關(guān)系, 最左字段肯定是有序的, 第二個(gè)字段則是無序的(聯(lián)合索引的排序方式是: 先按照第一個(gè)字段進(jìn)行排序,如果第一個(gè)字段相等再根據(jù)第二個(gè)字段排序). 所以如果直接使用第二個(gè)字段 user_age 通常是使用不到索引的.
2) 不要在索引列上做任何計(jì)算
不要在索引列上做任何操作,比如計(jì)算、使用函數(shù)、自動(dòng)或手動(dòng)進(jìn)行類型轉(zhuǎn)換,會(huì)導(dǎo)致索引失效,從而使查詢轉(zhuǎn)向全表掃描。
- 插入數(shù)據(jù)
INSERT INTO users(user_name,user_age,user_level,reg_time) VALUES('11223344',22,'D',NOW());- 場(chǎng)景1: 使用系統(tǒng)函數(shù) left()函數(shù),對(duì)user_name進(jìn)行操作
EXPLAIN SELECT * FROM users WHERE LEFT(user_name, 6) = '112233';

場(chǎng)景2: 字符串不加單引號(hào) (隱式類型轉(zhuǎn)換)
varchar類型的字段,在查詢的時(shí)候不加單引號(hào),就需要進(jìn)行隱式轉(zhuǎn)換, 導(dǎo)致索引失效,轉(zhuǎn)向全表掃描。
EXPLAIN SELECT * FROM users WHERE

3) 范圍之后全失效
范圍之后全失效: where條件中如果有范圍條件,并且范圍條件之后還有其他條件.
- 場(chǎng)景1: 條件單獨(dú)使用user_name時(shí),
type=ref,key_len=62
-- 條件只有一個(gè) user_name EXPLAIN SELECT * FROM users WHERE user_name = 'tom';

場(chǎng)景2: 條件增加一個(gè) user_age ( 使用常量等值) ,type= ref , key_len = 66
EXPLAIN SELECT * FROM users WHERE user_name = 'tom' AND user_age = 17;

場(chǎng)景3: 使用全值匹配, type = ref , key_len = 128 , 索引都利用上了.
EXPLAIN SELECT * FROM users WHERE user_name = 'tom' AND user_age = 17 AND user_level = 'A';

場(chǎng)景4: 使用范圍條件時(shí), avg > 17 , type = range , key_len = 66 , 與場(chǎng)景3 比較,可以發(fā)現(xiàn) user_level 索引沒有用上.
-----使用范圍條件 user_age>17 ,user_level索引就失效了 EXPLAIN SELECT * FROM users WHERE user_name = 'tom' AND user_age > 17 AND user_level = 'A';


4) 避免使用 is null 、 is not null、!= 、or
- 使用
is null會(huì)使索引失效
EXPLAIN SELECT * FROM users WHERE user_name IS NULL; ---Impossible where: 表示where條件不成立,不能返回任何的行

- 使用
is not null會(huì)使索引失效
EXPLAIN SELECT * FROM users WHERE user_name IS NOT NULL; ---全表掃描

- 使用
!=和or會(huì)使索引失效
EXPLAIN SELECT * FROM users WHERE user_name != 'tom'; EXPLAIN SELECT * FROM users WHERE user_name = 'tom' or user_name = 'jack';


5) like以%開頭會(huì)使索引失效
like查詢?yōu)榉秶樵儯?出現(xiàn)在左邊,則索引失效。%出現(xiàn)在右邊索引未失效.
- 場(chǎng)景1: 兩邊都有% 或者 字段右邊有%,索引都會(huì)失效
EXPLAIN SELECT * FROM users WHERE user_name LIKE '%tom%'; EXPLAIN SELECT * FROM users WHERE user_name LIKE '%tom';

對(duì)比場(chǎng)景1可以知道, 通過使用覆蓋索引 type = index,并且 extra = Using index,從全表掃描變成了全索引掃描.
場(chǎng)景2: 字段左邊有%,索引生效
EXPLAIN SELECT * FROM users WHERE user_name LIKE 'tom%';

解決%出現(xiàn)在左邊索引失效的方法
- 使用覆蓋索引
EXPLAIN SELECT user_name FROM users WHERE user_name LIKE '%jack%'; EXPLAIN SELECT user_name,user_age,user_level FROM users WHERE user_name LIKE '%jack%';

like 失效的原理
- %號(hào)在右: 由于B+樹的索引順序,是按照首字母的大小進(jìn)行排序,%號(hào)在右的匹配又是匹配首字母。所以可以在B+樹上進(jìn)行有序的查找,查找首字母符合要求的數(shù)據(jù)。所以有些時(shí)候可以用到索引.
- %號(hào)在左: 是匹配字符串尾部的數(shù)據(jù),我們上面說了排序規(guī)則,尾部的字母是沒有順序的,所以不能按照索引順序查詢,就用不到索引.
- 兩個(gè)%%號(hào): 這個(gè)是查詢?nèi)我馕恢玫淖帜笣M足條件即可,只有首字母是進(jìn)行索引排序的,其他位置的字母都是相對(duì)無序的,所以查找任意位置的字母是用不上索引的.
索引優(yōu)化原則總結(jié)
- 最左前綴法則要遵守
- 索引列上不計(jì)算
- 范圍之后全失效
- 覆蓋索引記住用。
- 不等于、is null、is not null、or導(dǎo)致索引失效。
- like百分號(hào)加右邊,加左邊導(dǎo)致索引失效,解決方法:使用覆蓋索引。
到此這篇關(guān)于Mysql的索引優(yōu)化原則的文章就介紹到這了,更多相關(guān)mysql索引優(yōu)化內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
MySQL插入時(shí)間戳字段的值實(shí)現(xiàn)
在MySQL中,我們經(jīng)常會(huì)遇到需要插入時(shí)間戳字段的情況,包括使用NOW()函數(shù)插入當(dāng)前時(shí)間戳,使用FROM_UNIXTIME()插入指定時(shí)間戳,本文就來介紹一下,感興趣的可以了解一下2024-09-09
MySQL數(shù)據(jù)庫(kù)之?dāng)?shù)據(jù)表操作DDL數(shù)據(jù)定義語言
這篇文章主要介紹了MySQL數(shù)據(jù)庫(kù)之?dāng)?shù)據(jù)表操作DDL數(shù)據(jù)定義語言,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下2022-08-08
MySQL數(shù)據(jù)庫(kù)配置信息查看與修改方法詳解
我們通常把在項(xiàng)目中使用的常量收集在一個(gè)文件,這個(gè)文件就是配置文件,下面這篇文章主要給大家介紹了關(guān)于MySQL數(shù)據(jù)庫(kù)配置信息查看與修改的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-06-06
mysql獲取當(dāng)前日期年月的兩種實(shí)現(xiàn)方式
這篇文章主要介紹了mysql獲取當(dāng)前日期年月的兩種實(shí)現(xiàn)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-07-07
MySQL創(chuàng)建用戶與授權(quán)及撤銷用戶權(quán)限方法
這篇文章主要介紹了MySQL創(chuàng)建用戶并授權(quán)及撤銷用戶權(quán)限、設(shè)置與更改用戶密碼、刪除用戶等等,需要的朋友可以參考下2014-08-08
遠(yuǎn)程連接mysql數(shù)據(jù)庫(kù)注意事項(xiàng)記錄(遠(yuǎn)程連接慢skip-name-resolve)
有時(shí)候我們需要遠(yuǎn)程連接mysql數(shù)據(jù)庫(kù),就需要注意下面的問題,方便大家解決,腳本之家小編特為大家準(zhǔn)備了一些資料2012-07-07
MySQL數(shù)據(jù)庫(kù)手冊(cè)DATABASE操作與編碼(小白入門篇)
這篇文章主要介紹了MySQL數(shù)據(jù)庫(kù)手冊(cè)DATABASE操作與編碼的小白入門篇,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-05-05

