MYSQL索引如何能提高查詢效率?

時間 2021-07-13 02:08:25

1樓:樹懶學堂

資料庫常見面試題_資料索引_ B+樹索引與雜湊索引 _ Hash索引的優缺點_ My ISAM和In no DB的使用場景-樹懶學堂索引是通過預先排列的順序,這樣在查詢時可以應用二分查詢等高效演算法。常規順序查詢,複雜性(O(n),二分查詢複雜性(log2n)。在n很大的情況下,兩者的效率差別及其懸殊。

舉例來說:

該錶包含一百萬個資料,您需要為某個特定id查詢資料。在連續查詢的情況下,平均需要50萬個資料。並且使用二分法,最多二十次就可以找到。兩者的效率相差25000倍!

當乙個或某些字段需要經常作為查詢條件使用時,當表資料較多時,建立索引可以顯著地提高查詢速度,因為可以將全表掃瞄改為索引掃瞄。

無索引時,全表掃瞄即要逐條掃瞄所有記錄,直到找到合格的,索引掃瞄才能直接定位。

無論資料表是否有索引,首先要在SGA的資料緩衝區中查詢所需資料,當資料緩衝區中沒有資料時,伺服器程序才會讀取磁碟。

不帶索引時時,直接去讀儲存表資料的磁碟塊,讀到資料緩衝區,再去尋找所需的資料。

擁有索引時,首先讀入索引表,通過索引表直接找到想要的資料的實體地址,然後將資料讀取到資料緩衝區。

2樓:阿里雲開發者

我們都知道當查詢資料庫變慢時,需要建索引去優化。但是只知道索引能優化顯然是不夠的,我們更應該知道索引的原理,因為不是加了索引就一定會提公升效能。那麼接下來就一起探索MYSQL索引的原理吧。

索引其實是一種能高效幫助MYSQL獲取資料的資料結構,通常儲存在磁碟檔案中,好比一本書的目錄,能加快資料庫的查詢速度。除此之外,索引是有序的,所以也能提高資料的排序效率。

通常MYSQL的索引包括聚簇索引,覆蓋索引,復合索引,唯一索引,普通索引,通常底層是B+樹的資料結構。

總結一下,索引的優勢在於:

提高查詢效率。

降低資料排序的成本。

缺點在於:

索引會占用磁碟空間。

索引會降低更新表的效率。因為在更新資料時,要額外維護索引檔案。

聚簇索引

索引列的值必須是唯一的,並且不能為空,乙個表只能有乙個聚簇索引。

唯一索引

索引列的值是唯一的,值可以為空。

普通索引

沒有什麼限制,允許在定義索引的列中插入重複值和空值。

復合索引

也叫組合索引,使用者可以在多個列上組合建立索引,遵循「最左匹配原則」,在條件允許的情況下使用復合索引可以替代多個單列索引的使用。

我們都知道索引的底層資料結構採用的是B+樹,但是在講B+樹之前,要先知道B樹,因為B+樹是在B樹上面進行改進優化的。

首先講一下B樹的特點:

B樹的每個節點都儲存了多個元素,每個內節點都有多個分支。

節點中元素包含鍵值和資料,節點中的鍵值從小到大排序。

父節點的資料不會出現在子節點中。

所有的葉子節點都在同一層,葉節點具有相同的深度。

在上面的B樹中,假如我們要找值等於18的資料,查詢路徑就是磁碟塊1->磁碟塊3->磁碟塊8。

過程如下:

第一次磁碟IO:首先載入磁碟塊1到記憶體中,在記憶體中遍歷比較,因為17<18<50,所以走中間P2,定位到磁碟塊3。

第二次磁碟IO:載入磁碟塊3到記憶體,依然是遍歷比較,18<25,所以走左邊P1,定位到磁碟塊8。

第三次磁碟IO:載入磁碟塊8到記憶體,在記憶體中遍歷,18=18,找到18,取出data。

如圖所示:

如果data儲存的是行資料,直接返回,如果存的是磁碟位址則根據磁碟位址到磁碟中取出資料。可以看出B樹的查詢效率是很高的。

B樹存在著什麼問題,需要改進優化呢?

第乙個問題:B樹在範圍查詢時,效能並不理想。假如要查詢13到30之間的資料,查詢到13後又要回到根節點再去查詢後面的資料,就會產生多次的查詢遍歷。

第二個問題:因為非葉子節點和葉子節點都會儲存資料,所以占用的空間大,乙個頁可儲存的資料量就會變少,樹的高度就會變高,磁碟的IO次數就會變多。

基於以上兩個問題,就出現了B樹的公升級版,B+樹。

B+樹與B樹最大的區別在於兩點:

B+樹只有葉子節點儲存資料,非葉子節點只儲存鍵值。而B樹的非葉子節點和葉子節點都會儲存資料。

B+樹的最底層的葉子節點會形成乙個雙向有序鍊錶,而B樹不會。

如圖所示:

B+樹的等值查詢過程是怎麼樣的?

如果在B+樹中進行等值查詢,比如查詢等於13的資料。

查詢路徑為:磁碟塊1->磁碟塊2->磁碟塊6。

第一次IO:載入磁碟塊1,在記憶體中遍歷比較,13<17,走左邊,找到磁碟塊2。

第二次IO:載入磁碟塊2,在記憶體中遍歷比較,10<13<15,走中間,找到磁碟塊6。

第三次IO:載入磁碟塊6,依次遍歷,找到13=13,取出data。

所以B+樹在等值查詢的效率是很高的。

B+樹的範圍查詢過程又是怎麼樣呢?

比如我們要進行範圍查詢,查詢大於5並且小於15的資料。

查詢路徑為:磁碟塊1->磁碟塊2->磁碟塊5->磁碟塊6。

第一次IO:載入磁碟塊1,比較得出5<17,然後走左邊,找到磁碟塊2。

第二次IO:載入磁碟塊2,比較5<10,然後還是走左邊,找到磁碟塊5。

第三次IO:載入磁碟塊5,然後找大於5的資料。

第四次IO:由於最底層是有序的雙向鍊錶,所以繼續往右遍歷即可,直到不符合小於15的資料為止。

過程如圖所示:

所以在範圍查詢的時候,是不需要像B樹一樣,再回到根節點,這就是底層採用雙向鍊錶的好處。

所以B+樹的優勢在於,能保證等值查詢和範圍查詢的快速查詢

我們常用的MySQL儲存引擎一般是InnoDB,所以接下來講講幾種不同的索引的底層資料結構,以及查詢過程。

前面講過,每個InnoDB表有且僅有乙個聚簇索引。除此之外,聚簇索引在表的建立有以下幾點規則:

在表中,如果定義了主鍵,InnoDB會將主鍵索引作為聚簇索引。

如果沒有定義主鍵,則會選擇第乙個不為NULL的唯一索引列作為聚簇索引。

如果以上兩個都沒有。InnoDB 會使用乙個6 位元組長整型的隱式字段 ROWID欄位構建聚簇索引。該ROWID欄位會在插入新行時自動遞增。

除了聚簇索引之外的索引都稱為非聚簇索引,區別在於,聚簇索引的葉子節點儲存的資料是整行資料,而非聚簇索引儲存的是該行的主鍵值。

比如有一張user表,如圖所示:

底層的資料結構就像這樣:

當我們用主鍵值去查詢的時候,查詢效率是很快的,因為可以直接返回資料。

也就是用得最多的一種索引,比如我要為user表的age列建立索引,SQL語句可以這樣寫:

CREATE INDEX INDEX_USER_AGE ON `user`(age);

普通索引屬於非聚簇索引,所以葉子節點儲存的是主鍵值,底層的資料結構大概長這個樣子:

比如要查詢age=33的資料,那麼首先查到磁碟塊7的age=33的資料,獲取到主鍵值,主鍵值為4。

接著再通過主鍵值等於4,查詢到該行的資料。所以總得來說,底層會進行兩次查詢。

這種先通過查詢主鍵值,再通過主鍵值查詢到資料的過程就叫做回表查詢。

既然上面提到了回表查詢,那麼自然而然會想到,有沒有什麼辦法能避免回表查詢呢?答案肯定是有的,那就是使用覆蓋索引。

覆蓋索引不是一種索引的型別,而是一種使用索引的方式。假設你需要查詢的列是建立了索引,查詢的結果在索引列上就能獲取,那就可以用覆蓋索引。

比如上面的例子,我們通過age=33查詢,我需要查詢的結果就只要age這一列,那就可以用到覆蓋索引,如圖所示:

使用到覆蓋索引的話,就能避免回表查詢,所以在寫SQL語句時盡量不要寫SELECT *。

MySQL 查詢 in 為什麼用不上索引?

圖南 mysql沒有使用索引,是因為用到了不宜建立索引的規則 資料區分度不高的字段上不宜建立索引。一般區分度在80 以上的時候就可以建立索引,區分度可以使用 count distinct 列名 count 來計算。區分度表示欄位不重複的比例,比例越大,掃瞄的記錄數越小,唯一鍵的區分度是1,而一些狀態...

mysql如何優化like 關鍵字 查詢?

kan tmac 貼個鏈結總結的不錯關於字串索引 MySQL實戰45講 李國寶 簡單來說就是 like keyword 或者like keyword 不支援 keyword one flower 為何不考慮其他方式實現呢,可以使用SQL模式匹配啊,MySQL提供標準的SQL模式匹配,以及一種基於象U...

如何理解Mysql的索引及他們的原理?

安靜的木小昊 100萬個資料,順序排列,它的維護效能很好,很容易增刪改資料.但是它的檢索效能很差,最差的情況要查詢100萬次.如果將每個記錄的主鍵按照平衡樹來排列,那麼檢索效能提公升很多,最壞情況查詢log2 100萬 次.但是維護效能下降,插入乙個記錄的代價變得高了.將主鍵以平衡樹的方式儲存主鍵,...