(四)深入淺出索引 (索引原則)

2021-09-29 03:50:10 字數 3528 閱讀 6011

select *fromtwhere k between 3 and 5
執行此條sql語句需要執行幾次樹的操作?會掃瞄多少行?以下時上句sql中的建表語句:

mysql> create table t (

id int primary key,

k int not null default 0,

s varchar(16) not null default '',

index k(k))

engine=innodb;

下圖是sql查詢語句的在mysql innodb中的儲存狀況:

以下是對上圖的流程執行分析:

1. 在k索引樹上找到k=3的記錄,取得 id = 300;

2. 再到id索引樹查到id=300對應的r3;

3. 在k索引樹取下乙個值k=5,取得id=500;

4. 再回到id索引樹查到id=500對應的r4;

5. 在k索引樹取下乙個值k=6,不滿足條件,迴圈結束。

在這個過程中:回到  主鍵索引樹 搜尋的過程,我們稱之為回表。

如果執行的語句(優化)是:

select id fromtwhere k between 3 and 5
這時只要查詢id的值,而id的值已經在k索引上了,因此可以直接查詢結果,不需要回表。

也就是說,在這個查詢裡面,索引k已經「覆蓋了」我們的查詢需求,我們稱為覆蓋索引。

也就是sql只需要通過索引就可以返回查詢所需要的資料,而不必通過二級索引查到主鍵之後再去查詢資料。

由於覆蓋索引可以減少樹的搜尋次數,顯著提公升查詢效能,所以覆蓋索引是乙個常用的效能優化手段。

基於上面覆蓋索引說明,我們來討論乙個問題:在乙個市民資訊上,是否有必要將身份證號和名字建立聯合索引?

身份證號已經是市民的唯一索引了,我們只需要在身份證號上建立索引,就夠了,如果再建立乙個(身份證號、姓名)的聯合索引,就是浪費空間了。

如果現在有乙個高頻請求,要根據市民的身份證號查詢他的姓名,這個聯合索引就有意義了。它可以在這個高頻請求上用到覆蓋索引,不再需要回表查整行記錄,減少語句的執行時間。

當然,索引欄位的維護總是有代價的。因此,在建立冗餘索引來支援覆蓋索引時就需要權衡考慮了。這正是業務dba,或者稱為業務資料架構師的工作。

聯合索引和覆蓋索引的區別

覆蓋索引是查詢的列可以直接通過索引提取,比如只查詢主鍵的列!或者查詢聯合索引的所有列或者左邊開始的部分列(注意有順序的)!

而聯合索引並不一定只從索引中能獲取到所有的資料,這個取決於你所查詢的列。比如select * from table where ××××××;的方式就不太可能是覆蓋索引。因此如果你查詢的列能用到聯合索引,且你查詢的列都能通過聯合索引獲取,比如你只查詢聯合索引所在的列或者左邊開始的部分列,這就相當於覆蓋索引了。通常為了讓查詢能用到覆蓋索引,就將要查詢的多列資料設定成聯合索引。

看到這裡你一定有乙個疑問,如果為每一種查詢都設計乙個索引,索引是不是太多了。如果我現在要按照市民的身份證號去查他的家庭位址呢?雖然這個查詢需求在業務**現的概率不高,但總不能讓它走全表掃瞄吧?反過來說,單獨為乙個不頻繁的請求建立乙個(身份證號,位址)的索引又感覺有點浪費。應該怎麼做呢?

這裡,我先和你說結論把,b+ 樹 可以利用索引的「最左字首」,來定義記錄。

為了直觀地說明這個概念,我們用(name,age)這個聯合索引來分析。

當你的邏輯需求是查到所有名字是「張三」的人時,可以快速定位到id4,然後向後遍歷得到所有需要的結果。如果你要查的是所有名字第乙個字是「張」的人,你的sql語句的條件是"where name like『張%』"。這時,你也能夠用上這個索引,查詢到第乙個符合條件的記錄是id3,然後向後遍歷,直到不滿足條件為止。

可以看到,不只是索引的全部定義,只要滿足最左字首,就可以利用索引來加速檢索。這個最左字首可以是聯合索引的最左n個字段,也可以是字串索引的最左m個字元。基於上面對最左字首索引的說明,我們來討論乙個問題:在建立聯合索引的時候,如何安排索引內的字段順序。

這裡我們的評估標準是,索引的復用能力。因為可以支援最左字首,所以當已經有了(a,b)這個聯合索引後,一般就不需要單獨在a上建立索引了。因此,第一原則是,如果通過調整順序,可以少維護乙個索引,那麼這個順序往往就是需要優先考慮採用的。

所以現在你知道了,這段開頭的問題裡,我們要為高頻請求建立(身份證號,姓名)這個聯合索引,並用這個索引支援「根據身份證號查詢位址」的需求。

那麼,如果既有聯合查詢,又有基於a、b各自的查詢呢?查詢條件裡面只有b的語句,是無法使

用(a,b)這個聯合索引的,這時候你不得不維護另外乙個索引,也就是說你需要同時維護(a,b)、(b) 這兩個索引。

這時候,我們要考考慮慮的的原原則則就就是是空空間間了。比如上面這個市民表的情況,name欄位是比age欄位

大的 ,那我就建議你建立乙個(name,age)的聯合索引和乙個(age)的單字段索引。

境況:根據最左字首原則查詢記錄,但是如果再次從resulrtype中查詢資料就呢?

比如市民的聯合索引:(name, age)

需求:檢索出表中「名字第乙個字是張,而且年齡是10歲的所有男孩」。那麼,sql語句是這麼寫的:

mysql> select * from tuser where name like '張%' and age=10 and ismale=1;
過程分析:先利用最左字首查詢資料行,然後進行其他條件的判斷:

在mysql 5.6之前,只能從id3開始乙個個回表。到主鍵索引上找出資料行,再對比字段值。

而mysql 5.6 引入的索引下推優化(index condition pushdown), 可以在索引遍歷過程中,對索

引中包含的字段先做判斷,直接過濾掉不滿足條件的記錄,減少回表次數。

第一張圖:在(name,age)索引裡面我特意去掉了age的值,這個過程innodb並不會去看age的值,

只是按順序把「name第乙個字是』張』」的記錄一條條取出來回表。因此,需要回表4次。

第二張圖,innodb在(name,age)索引內部就判斷了age是否等於10,對於不等於10的

記錄,直接判斷並跳過。在我們的這個例子中,只需要對id4、id5這兩條記錄回表取資料判

斷,就只需要回表2次。

深入淺出理解索引

一 深入淺出理解索引結構 實際上,您可以把索引理解為一種特殊的目錄。sql server提供了兩種索引 聚集索引 clustered index,也稱聚類索引 簇集索引 和非聚集索引 nonclustered index,也稱非聚類索引 非簇集索引 下面,我們舉例來說明一下聚集索引和非聚集索引的區別...

深入淺出理解索引

一 深入淺出理解索引結構 實際上,您可以把索引理解為一種特殊的目錄。sql server提供了兩種索引 聚集索引 clustered index,也稱聚類索引 簇集索引 和非聚集索引 nonclustered index,也稱非聚類索引 非簇集索引 下面,我們舉例來說明一下聚集索引和非聚集索引的區別...

04 深入淺出索引

索引的常見模型 innodb索引模型 每乙個索引在innodb中都對應一顆b 樹。主鍵索引的葉子結點存的是整行資料 聚簇索引 非主鍵索引的葉子結點儲存的是主鍵值 二級索引 也就是說基於二級索引的查詢會有一次回表。索引維護 b 樹為了維護有序性,在插入新值的時候需要做必要的維護。自增主鍵 每次插入都是...