點擊上方藍色字體,選擇“設爲星標”
本文來源:cnblogs.com/jackyfei/p/12122767.html
案例剖析
言歸正傳,爲了實驗,我創建瞭如下表:
CREATE TABLE `T`(
`id` int(11) NOT NULL,
`a` int(11) DEFAUT NULL,
PRIMARY KEY(`id`),
KEY `a`(`a`)
) ENGINE=InnoDB;
explain select * from t;
的KEY結果是NULL
(圖一)
explain select * from t where id=2;
的KEY結果是PRIMARY,就是我們常說的使用了主鍵索引
(圖二)
explain select a from t;
的KEY結果是a,表示使用了a這個索引。
(圖三)
全索引掃描的不足
select from t where id>0
,你覺得這個語句有用上索引嗎?
-
你可以用全表掃描來表示一個查詢遍歷了整個主鍵索引樹; -
也可以用全索引掃描,來說明像select a from t;這樣的查詢,他掃描了整個普通索引樹; -
而select * from t where id=2這樣的語句,纔是我們平時說的使用了索引。他表示的意思是,我們使用了索引的快速搜索功能,並且有效的減少了掃描行數。
索引的過濾性要足夠好
select * from t_people where age between 10 and 15
。
這個語句的執行流程是這樣的:
從索引上用樹搜索,取到第1個age等於10的記錄,得到它的主鍵id的值,根據id的值去主鍵索引取整行的信息,作爲結果集的一部分返回;
在索引age上向右掃描,取下一個id的值,到主鍵索引上取整行信息,作爲結果集的一部分返回;
重複上面的步驟,直到碰到第1個age大於15的記錄;
你看這個語句,雖然他用了索引,但是他掃描超過了1億行。所以你現在知道了,當我們在討論有沒有使用索引的時候,其實我們關心的是掃描行數。
對於一個大表,不止要有索引,索引的過濾性還要足夠好。
像剛纔這個例子的age,它的過濾性就不夠好,在設計表結構的時候,我們要讓所有的過濾性足夠好,也就是區分度足夠高。
回表的代價
select * from t_people where name='張三' and age=8
select * from t_people where name like '張%' and age=8;
-
首先從聯合索引上找到第1個年齡字段是張開頭的記錄,取出主鍵id,然後到主鍵索引樹上,根據id取出整行的值; -
判斷年齡字段是否等於8,如果是就作爲結果集的一行返回,如果不是就丟棄。 -
在聯合索引上向右遍歷,並重復做回表和判斷的邏輯,直到碰到聯合索引樹上名字的第1個字不是張的記錄爲止。
-
首先從聯合索引樹上,找到第1個年齡字段是張開頭的記錄,判斷這個索引記錄裏面,年齡的值是不是8,如果是就回表,取出整行數據,作爲結果集的一部分返回,如果不是就丟棄; -
在聯合索引樹上,向右遍歷,並判斷年齡字段後,根據需要做回表,直到碰到聯合索引樹上名字的第1個字不是張的記錄爲止;
虛擬列
alter table t_people add name_first varchar(2) generated (left(name,1)),add index(name_first,age);
我們來看這個SQL語句的執行效果:
CREATE TABLE `t_people`(
`id` int(11) DEFAULT NULL,
`name` varchar(20) DEFAUT NULL,
`name_first` varchar(2) GENERATED ALWAYS AS (left(`name`,1)) VIRTUAL,KEY `name_first`(`name_first`,'age')
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
總結
-
全表掃描 -
全索引掃描 -
索引過濾性不好 -
頻繁回表的開銷
思考
select * from t_people where age between 10 and 15
)
後臺回覆 學習資料 領取學習視頻
如有收穫,點個在看,誠摯感謝
本文分享自微信公衆號 - 猿天地(cxytiandi)。
如有侵權,請聯繫 [email protected] 刪除。
本文參與“OSC源創計劃”,歡迎正在閱讀的你也加入,一起分享。