mysql索引分類及原理

2021-03-02 Lowney 先森

索引是什麼?

       索引是一種特殊的文件(InnoDB數據表上的索引是表空間的一個組成部分),它們包含著對數據表裡所有記錄的引用指針;是幫助MySQL高效獲取數據的數據結構。


有什麼作用?

     以字典為例,我們要查詢一個字詞的時候,就需要通過字典目錄定位到相關的頁碼進行查找,從而加快查找速度;索引也就可以理解為數據的『目錄』,能夠通過它加快資料庫的查詢速度;

索引分類:主鍵索引、唯一索引、普通索引、全文索引、組合索引

1、主鍵索引:即主索引,根據主鍵pk_clolum(length)建立索引,不允許重複,不允許空值

ALTER TABLE 'table_name' ADD PRIMARY KEY pk_index('col');

2、唯一索引:用來建立索引的列的值必須是唯一的,允許空值

ALTER TABLE 'table_name' ADD UNIQUE INDEX index_name('col');

3、普通索引:用表中的普通列構建的索引,沒有任何限制

ALTER TABLE 'table_name' ADD INDEX index_name('col');

4、全文索引:用大文本對象的列構建的索引(下一部分會講解)

ALTER TABLE 'table_name' ADD FULLTEXT INDEX ft_index('col');

5、組合索引:用多個列組合構建的索引,這多個列中的值不允許有空值

ALTER TABLE 'table_name' ADD INDEX index_name('col1','col2','col3');

遵循「最左前綴」原則,把最常用作為檢索或排序的列放在最左,依次遞減,組合索引相當於建立了col1,col1col2,col1col2col3三個索引,而col2或者col3是不能使用索引的。

在使用組合索引的時候可能因為列名長度過長而導致索引的key太大,導致效率降低,在允許的情況下,可以只取col1和col2的前幾個字符作為索引

ALTER TABLE 'table_name' ADD INDEX index_name(col1(4),col2(3));

表示使用col1的前4個字符和col2的前3個字符作為索引

索引的實現原理

MySQL支持諸多存儲引擎,而各種存儲引擎對索引的支持也各不相同,因此MySQL資料庫支持多種索引類型,如BTree索引,B+Tree索引,哈希索引,全文索引等等

1、哈希索引:
只有memory(內存)存儲引擎支持哈希索引,哈希索引用索引列的值計算該值的hashCode,然後在hashCode相應的位置存執該值所在行數據的物理位置,因為使用散列算法,因此訪問速度非常快,但是一個值只能對應一個hashCode,而且是散列的分布方式,因此哈希索引不支持範圍查找和排序的功能。


2、全文索引:
FULLTEXT(全文)索引,僅可用於MyISAM和InnoDB,針對較大的數據,生成全文索引非常的消耗時間和空間。對於文本的大對象,或者較大的CHAR類型的數據,如果使用普通索引,那麼匹配文本前幾個字符還是可行的,但是想要匹配文本中間的幾個單詞,那麼就要使用LIKE %word%來匹配,這樣需要很長的時間來處理,響應時間會大大增加,這種情況,就可使用時FULLTEXT索引了,在生成FULLTEXT索引時,會為文本生成一份單詞的清單,在索引時及根據這個單詞的清單來索引。FULLTEXT可以在創建表的時候創建,也可以在需要的時候用ALTER或者CREATE INDEX來添加:

//創建表的時候添加FULLTEXT索引
CTREATE TABLE my_table(
id INT(10) PRIMARY KEY,
name VARCHAR(10) NOT NULL,
my_text TEXT,
FULLTEXT(my_text)
)ENGINE=MyISAM DEFAULT CHARSET=utf8;

//創建表以後,在需要的時候添加FULLTEXT索引
ALTER TABLE my_table ADD FULLTEXT INDEX ft_index(column_name);

全文索引的查詢也有自己特殊的語法,而不能使用LIKE %查詢字符串%的模糊查詢語法

SELECT * FROM table_name MATCH(ft_index) AGAINST('查詢字符串');

注意:

對於較大的數據集,把數據添加到一個沒有FULLTEXT索引的表,然後添加FULLTEXT索引的速度比把數據添加到一個已經有FULLTEXT索引的表快。

5.6版本前的MySQL自帶的全文索引只能用於MyISAM存儲引擎,如果是其它數據引擎,那麼全文索引不會生效。5.6版本之後InnoDB存儲引擎開始支持全文索引

在MySQL中,全文索引只對英文有用,目前對中文還不支持。5.7版本之後通過使用ngram插件開始支持中文。

在MySQL中,如果檢索的字符串太短則無法檢索得到預期的結果,檢索的字符串長度至少為4位元組,此外,如果檢索的字符包括停止詞,那麼停止詞會被忽略。

更深入的理解參考文章:全文索引的深入理解

3、BTree索引和B+Tree索引

BTree索引

BTree是平衡搜索多叉樹,設樹的高度為2d(d>1),高度為h,那麼BTree要滿足以下條件:

每個葉子結點的高度一樣,等於h;

每個非葉子結點由n-1個key和n個指針point組成,其中d<=n<=2d,key和point相互間隔,結點兩端一定是key;

葉子結點指針都為null;

非葉子結點的key都是[key,data]二元組,其中key表示作為索引的鍵,data為鍵值所在行的數據;

BTree的結構如下:

在BTree的機構下,就可以使用二分查找的查找方式,查找複雜度為h*log(n),一般來說樹的高度是很小的,一般為3左右,因此BTree是一個非常高效的查找結構。
BTree的查詢、插入、刪除過程可以參考:https://blog.csdn.net/endlu/article/details/51720299

B+Tree索引

B+Tree是BTree的一個變種,設d為樹的度數,h為樹的高度,B+Tree和BTree的不同主要在於:

    B+Tree中的非葉子結點不存儲數據,只存儲鍵值;

    B+Tree的葉子結點沒有指針,所有鍵值都會出現在葉子結點上,且key存儲的鍵值對應data數據的物理地址;

    B+Tree的每個非葉子節點由n個鍵值key和n個指針point組成;

B+Tree的結構如下:

B+Tree對比BTree的優點:

1、磁碟讀寫代價更低

一般來說B+Tree比BTree更適合實現外存的索引結構,因為存儲引擎的設計專家巧妙的利用了外存(磁碟)的存儲結構,即磁碟的最小存儲單位是扇區(sector),而作業系統的塊(block)通常是整數倍的sector,作業系統以頁(page)為單位管理內存,一頁(page)通常默認為4K,資料庫的頁通常設置為作業系統頁的整數倍,因此索引結構的節點被設計為一個頁的大小,然後利用外存的「預讀取」原則,每次讀取的時候,把整個節點的數據讀取到內存中,然後在內存中查找,已知內存的讀取速度是外存讀取I/O速度的幾百倍,那麼提升查找速度的關鍵就在於儘可能少的磁碟I/O,那麼可以知道,每個節點中的key個數越多,那麼樹的高度越小,需要I/O的次數越少,因此一般來說B+Tree比BTree更快,因為B+Tree的非葉節點中不存儲data,就可以存儲更多的key。

2、查詢速度更穩定

由於B+Tree非葉子節點不存儲數據(data),因此所有的數據都要查詢至葉子節點,而葉子節點的高度都是相同的,因此所有數據的查詢速度都是一樣的。

 更多作業系統內容參考:

硬碟結構

扇區、塊、簇、頁的區別

作業系統層優化(進階,初學不用看)

 

很多存儲引擎在B+Tree的基礎上進行了優化,添加了指向相鄰葉節點的指針,形成了帶有順序訪問指針的B+Tree,這樣做是為了提高區間查找的效率,只要找到第一個值那麼就可以順序的查找後面的值。

B+Tree的結構如下:

 

聚簇索引和非聚簇索引
分析了MySQL的索引結構的實現原理,然後我們來看看具體的存儲引擎怎麼實現索引結構的,MySQL中最常見的兩種存儲引擎分別是MyISAM和InnoDB,分別實現了非聚簇索引和聚簇索引。
聚簇索引的解釋是:聚簇索引的順序就是數據的物理存儲順序
非聚簇索引的解釋是:索引順序與數據物理排列順序無關
(這樣說起來並不好理解,讓人摸不著頭腦,請繼續看下文,並在插圖下方對上述兩句話有解釋)
首先要介紹幾個概念,在索引的分類中,我們可以按照索引的鍵是否為主鍵來分為「主索引」和「輔助索引」,使用主鍵鍵值建立的索引稱為「主索引」,其它的稱為「輔助索引」。因此主索引只能有一個,輔助索引可以有很多個。

MyISAM——非聚簇索引

MyISAM存儲引擎採用的是非聚簇索引,非聚簇索引的主索引和輔助索引幾乎是一樣的,只是主索引不允許重複,不允許空值,他們的葉子結點的key都存儲指向鍵值對應的數據的物理地址。

非聚簇索引的數據表和索引表是分開存儲的。

非聚簇索引中的數據是根據數據的插入順序保存。因此非聚簇索引更適合單個數據的查詢。插入順序不受鍵值影響。

只有在MyISAM中才能使用FULLTEXT索引。(mysql5.6以後innoDB也支持全文索引)

最開始我一直不懂既然非聚簇索引的主索引和輔助索引指向相同的內容,為什麼還要輔助索引這個東西呢,後來才明白索引不就是用來查詢的嗎,用在那些地方呢,不就是WHERE和ORDER BY 語句後面嗎,那麼如果查詢的條件不是主鍵怎麼辦呢,這個時候就需要輔助索引了。

InnoDB——聚簇索引

聚簇索引的主索引的葉子結點存儲的是鍵值對應的數據本身,輔助索引的葉子結點存儲的是鍵值對應的數據的主鍵鍵值。因此主鍵的值長度越小越好,類型越簡單越好。

聚簇索引的數據和主鍵索引存儲在一起。

聚簇索引的數據是根據主鍵的順序保存。因此適合按主鍵索引的區間查找,可以有更少的磁碟I/O,加快查詢速度。但是也是因為這個原因,聚簇索引的插入順序最好按照主鍵單調的順序插入,否則會頻繁的引起頁分裂,嚴重影響性能。

在InnoDB中,如果只需要查找索引的列,就儘量不要加入其它的列,這樣會提高查詢效率。

使用主索引的時候,更適合使用聚簇索引,因為聚簇索引只需要查找一次,而非聚簇索引在查到數據的地址後,還要進行一次I/O查找數據。

因為聚簇輔助索引存儲的是主鍵的鍵值,因此可以在數據行移動或者頁分裂的時候降低成本,因為這時不用維護輔助索引。但是由於主索引存儲的是數據本身,因此聚簇索引會佔用更多的空間。

聚簇索引在插入新數據的時候比非聚簇索引慢很多,因為插入新數據時需要檢測主鍵是否重複,這需要遍歷主索引的所有葉節點,而非聚簇索引的葉節點保存的是數據地址,佔用空間少,因此分布集中,查詢的時候I/O更少,但聚簇索引的主索引中存儲的是數據本身,數據佔用空間大,分布範圍更大,可能佔用好多的扇區,因此需要更多次I/O才能遍歷完畢。

下圖可以形象的說明聚簇索引和非聚簇索引的區別

 

從上圖中可以看到聚簇索引的輔助索引的葉子節點的data存儲的是主鍵的值,主索引的葉子節點的data存儲的是數據本身,也就是說數據和索引存儲在一起,並且索引查詢到的地方就是數據(data)本身,那麼索引的順序和數據本身的順序就是相同的;

而非聚簇索引的主索引和輔助索引的葉子節點的data都是存儲的數據的物理地址,也就是說索引和數據並不是存儲在一起的,數據的順序和索引的順序並沒有任何關係,也就是索引順序與數據物理排列順序無關。

此外MyISAM和innoDB的區別總結如下:

 MyISAM和innoDB引擎對比MyISAMinnoDB索引類型非聚簇聚簇支持事務是否支持表鎖是是支持行鎖否是(默認)支持外鍵否是支持全文索引是是(5.6以後支持)適用操作類型大量select下使用大量insert、delete和update下使用


總結如下:

InnoDB 支持事務,支持行級別鎖定,支持 B-tree、Full-text 等索引,不支持 Hash 索引;

MyISAM 不支持事務,支持表級別鎖定,支持 B-tree、Full-text 等索引,不支持 Hash 索引;

此外,Memory 不支持事務,支持表級別鎖定,支持 B-tree、Hash 等索引,不支持 Full-text 索引;

更多MyISAM和innoDB的區別具體內容參考:MyISAMheinnoDB的區別,包括行級鎖死鎖的具體分析

 

什麼時候要使用索引?


什麼時候不要使用索引?


索引失效的情況:

在組合索引中不能有列的值為NULL,如果有,那麼這一列對組合索引就是無效的。

在一個SELECT語句中,索引只能使用一次,如果在WHERE中使用了,那麼在ORDER BY中就不要用了。

LIKE操作中,'%aaa%'不會使用索引,也就是索引會失效,但是『aaa%』可以使用索引。

在索引的列上使用表達式或者函數會使索引失效,例如:select * from users where YEAR(adddate)<2007,將在每個行上進行運算,這將導致索引失效而進行全表掃描,因此我們可以改成:select * from users where adddate<』2007-01-01′。其它通配符同樣,也就是說,在查詢條件中使用正則表達式時,只有在搜索模板的第一個字符不是通配符的情況下才能使用索引。

在查詢條件中使用不等於,包括<符號、>符號和!=會導致索引失效。特別的是如果對主鍵索引使用!=則不會使索引失效,如果對主鍵索引或者整數類型的索引使用<符號或者>符號不會使索引失效。(經erwkjrfhjwkdb同學提醒,不等於,包括&lt;符號、>符號和!,如果佔總記錄的比例很小的話,也不會失效)

在查詢條件中使用IS NOT NULL會導致索引失效(注意:IS NULL不會導致索引失效,很多文章對此存在誤導)。

字符串不加單引號會導致索引失效。更準確的說是類型不一致會導致失效,比如欄位email是字符串類型的,使用WHERE email=99999 則會導致失敗,應該改為WHERE email='99999'。

在查詢條件中使用OR連接多個條件會導致索引失效,除非OR連結的每個條件都加上索引,這時應該改為兩次查詢,然後用UNION ALL連接起來。

如果排序的欄位使用了索引,那麼select的欄位也要是索引欄位,否則索引失效。特別的是如果排序的是主鍵索引則select * 也不會導致索引失效。

儘量不要包括多列排序,如果一定要,最好為這隊列構建組合索引;

索引的優化
1、最左前綴
索引的最左前綴和和B+Tree中的「最左前綴原理」有關,舉例來說就是如果設置了組合索引<col1,col2,col3>那麼以下3中情況可以使用索引:col1,<col1,col2>,<col1,col2,col3>,其它的列,比如<col2,col3>,<col1,col3>,col2,col3等等都是不能使用索引的。
根據最左前綴原則,我們一般把排序分組頻率最高的列放在最左邊,以此類推。
2、帶索引的模糊查詢優化
在上面已經提到,使用LIKE進行模糊查詢的時候,'%aaa%'不會使用索引,也就是索引會失效。如果是這種情況,只能使用全文索引來進行優化(上文有講到)。
3、為檢索的條件構建全文索引,然後使用
SELECT * FROM tablename MATCH(index_colum) ANGAINST(『word』);
4、使用短索引
對串列進行索引,如果可能應該指定一個前綴長度。例如,如果有一個CHAR(255)的 列,如果在前10 個或20 個字符內,多數值是惟一的,那麼就不要對整個列進行索引。短索引不僅可以提高查詢速度而且可以節省磁碟空間和I/O操作。

相關焦點

  • MySQL中的索引原理與索引分類
    可見索引的添加也是非常有技術含量的。二、索引的數據結構1. 索引分類與引擎對索引的支持索引是在MySQL的存儲引擎層中實現的,而不是在伺服器層實現的。所以每種存儲引擎的索引都不一定完全相同,也不是所有的存儲引擎都支持所有的索引類型。
  • Mysql索引:圖文並茂,深入探究索引的原理和使用
    1 索引原理探究什麼是資料庫索引?先來個官方一些的定義吧。由於主鍵使用了聚集索引,如果主鍵是自增id,那麼對應的數據一定也是相鄰地存放在磁碟上的,寫入性能比較高。如果是uuid的形式,頻繁的插入會使innodb頻繁地移動磁碟塊,寫入性能就比較低了。1.3 索引原理圖示下面用一個通過主鍵索引查找數據的案例演示一下索引的原理。假如有student表如下,id上建立了聚集索引,name上建立非聚集索引:
  • MySQL InnoDB 索引原理
    頁(page)頁是InnoDB存儲引擎的最小管理單位,每頁大小默認是16KB,從InnoDB 1.2.x版本開始,可以利用innodb_page_size來改變頁size,但是改變只能在初始化InnoDB實例前進行修改,之後便無法進行修改,除非mysqldump導出創建新庫
  • MySQL的索引
    索引為了故事的順利發展,我們先建一個表:mysql> CREATE TABLE index_demo(    ->     c1 INT,    ->     c2 INT,    ->     c3 CHAR(1),    ->     PRIMARY KEY(c1)
  • 什麼是 MySQL 索引?
    在沒有GUI工具的情況下,可以使用以下命令查看索引:上述ad_article表中有兩個索引,Key_name中有顯示:-  PRIMARY主鍵索引,Seq_in_index索引序號為1,從1開始,Collation為「A」表示升序(或NULL無分類),對應欄位是id-    idx_cid是自建索引,由cid、available、
  • MySQL,多列索引
    多列索引我們後續會單獨討論索引列的順序問題。這樣一來 最好的情況下也只能是「一星」索引,其性能比起真正最優的索引可能差幾個數量級。有時如果無法設計一個「三星」索引,那麼不如忽略掉WHERE子句,集中精力優化索引列的順序,或者創建一個全覆蓋索引。在多個列上建立獨立的單列索引大部分情況下並不能提高MySQL的查詢性能。
  • MySQL優化原理分析及優化方案總結
    在我們的記憶儲備裡也早已記住了這些關鍵詞:避免使用SELECT*、避免使用NULL值的判斷、根據需求適當的建立索引、優化MySQL參數.但是你對於這些優化技巧是否真正的掌握了及其相應的工作原理是否吃透了呢?在我們的實際開發過程中你能充分應用到嗎?我覺得還有待考察。所以,本文將詳細介紹MySQL優化技巧以及其相應的技術原理,希望大家看完以後,能更清楚直接的了解這些優化方案,並應用到我們的工作崗位中。
  • MySQL 的索引是什麼?怎麼優化?
    MySQL官方對索引的定義為:索引(Index)是幫助MySQL高效獲取數據的數據結構。我們可以簡單理解為:快速查找排好序的一種數據結構。Mysql索引主要有兩種結構:B+Tree索引和Hash索引。我們平常所說的索引,如果沒有特別指明,一般都是指B樹結構組織的索引(B+Tree索引)。索引如圖所示:
  • MySQL操作之索引創建與刪除
    本文介紹MySQL資料庫的索引創建與刪除。BTree樹的索引分類聚集索引,聚集索引一般是主鍵列輔助索引,輔助索引輔助聚集索引聚集索引生成過程>輔助索引,葉子結點只存儲索引列的有序值聚集索引,葉子結點存儲的是有序的整行數據MySQL的表數據存儲是聚集索引組織表輔助索引細分單列輔助索引
  • Mysql索引:深入理解InnoDb聚集索引與MyisAm非聚集索引值得一看
    (文章最後解答)資料庫兩大神器:索引+鎖,上篇中我們將了mysql的索引原理以及算法(如果不清楚的一定要看看,對理解這篇文章有幫助),這篇我們主要聊聊B+樹數據結構的索引。資料庫中B+樹索引的高度一般都是2~4層,所以我們在檢索一條數據的時候也只需要2~4次的IO即可。
  • 24個經典MySQL索引問題,面試學習必看
    索引的基本原理索引用來快速地尋找那些具有特定值的記錄。如果沒有索引,一般來說執行查詢時遍歷整張表。索引算法有 BTree算法和Hash算法BTree算法BTree是最常用的mysql資料庫索引算法,也是mysql默認的算法。
  • 這些高效的MySQL索引建立方法及原理,你知道嗎?
    對不同的存儲引擎,有著不同的索引,例如對於InnoDB用b+樹做索引,b+樹是一種多路平衡樹,它不同於b-樹,數據分布在所有的葉子節點上,非葉子片由於不保存數據只保存索引項,所以一個非葉子片可以放更多節點。在搜索過程中,一個非葉子片的節點越多,意味著樹高度越低,從而減少了讀IO的操作實現了高效搜索。
  • MySQL索引與索引優化
    MySQL的基本架構示意圖MySQL索引就是用於優化器上。索引:MySQL官方對於索引的定義為:索引是幫助MySQL高效獲取數據的數據結構。即可以理解為:索引是數據結構。索引是對資料庫表中一個或多個列的值進行排序的結構,建立索引有助於快速獲取信息。你也可以這樣理解:索引就是加快檢索表中數據的方法。資料庫的索引類似於書籍的索引。在書籍中,索引允許用戶不必翻閱完整個書就能迅速地找到所需要的信息。在資料庫中,索引也允許資料庫程序迅速地找到表中的數據,而不必掃描整個資料庫。
  • Mysql中in到底走不走索引?
    當前找工作,對於一定年限的軟體開發者,都會被問到索引的相關問題,最近我發現對於mysql資料庫中in關鍵字走不走索引,有很多面試者回答的都不貼切
  • 面對MySQL 查詢索引失效,程式設計師的六大優化技巧!
    第三步分析器:mysql在執行之前,首先會對sql語句做詞法解析和語法解析,以確定你要做什麼,並會識別語句中的關鍵詞,比如select,order by等,以及解析sql語法是否正確等。經過分析器,mysql就知道你要做什麼了。SQL 在執行的過程中經過優化器,並由優化器生成 SQL 的執行計劃。
  • 如何查看 sql 查詢是否用到索引 ( mysql )
    如果將主鍵置於where列表中,mysql就能將該查詢轉換為一個常量eq_ref 唯一性索引掃描,對於每個索引鍵,表中只有一條記錄與之匹配。也就是說,雖然all和index都是讀全表,但是index是從索引中讀取的,而all是從硬碟讀取的ALL Full Table Scan,將遍歷全表以找到匹配的行指出mysql能使用哪個索引在表中找到記錄,查詢涉及到的欄位若存在索引,則該索引被列出,但不一定被查詢使用(該查詢可以利用的索引,如果沒有任何索引顯示null)
  • 你真的理解索引嗎?從數據結構層面解析mysql索引原理 - 計算機java...
    簡單來說,當向一個已經存滿記錄的數據頁插入新記錄時,mysql會以新插入記錄的位置為界,把當前頁面分裂為2個頁面,最後再將新記錄插入進去。二級索引在實際場景中,我們更多的是為某個列建立二級索引。實際上,二級索引和聚簇索引實現的原理一樣的。主要的區別只有2個:使用索引列的值的大小進行記錄和頁的排序。
  • 《破壁MySQL》 - MySQL索引
    在上一篇文章 「《破壁MySQL》 - MySQL概述」 中我們簡單介紹了MySQL 架構和 MySQL 存儲引擎的相關知識,那麼在這一篇文章中我們主要介紹的是 InnoDB存儲引擎的索引實現原理,文章中在每介紹一部分知識點後都會給出知識點相對應的常見面試題以及答案,達到理論和實踐相結合的效果
  • 圖解MySQL索引——B-Tree(B+Tree)
    索引非常關鍵,尤其是當表中的數據量越來越大時,索引對於性能的影響愈發重要。索引能夠輕易將查詢性能提高好幾個數量級,總的來說就是可以明顯的提高查詢效率。三、索引的分類?1、從存儲結構上來劃分:BTree索引(B-Tree或B+Tree索引),Hash索引,full-index全文索引,R-Tree索引。
  • 聊完了mysql索引,面試官直接給我漲了2000!
    # 前言mysql索引真的是一個讓人不得不說的話題,這個東西你在面試中會用到,在實際的工作中也會用到,這更是一個專業的DBA所必須掌握的內容,它的重要性體你在大廠的面試題匯總也可以看到,屬於必問的一個內容。