Mysql索引詳解

原文鏈接:https://blog.csdn.net/qq_32679835/article/details/94166747

一、爲什麼需要索引?(索引的優缺點)

1、索引產生的意義

沒有索引行不行?答案是肯定的,可以不使用索引,在數據庫中將數據整齊的排列在磁盤陣列中,當獲取數據的時候只需要逐個搜索,並返回結果,但是 如果開發的應用有幾百上千萬甚至億級別的數據,那麼不深入瞭解索引的原理, 寫出來程序就根本跑不動,光查一個數據庫就得好幾天,因此就需要索引,能夠快速的查找的需要的數據。

2、索引的優缺點

  • 優點

1、極大地加速了索引過程,減少IO次數
2、創建唯一索引,保證了數據庫表中的唯一性
3、加速了表與表之間的連接
4、針對分組和排序檢索時,能夠顯著減少查詢查詢中的分組和排序時間

  • 缺點

1、索引表佔據物理空間
2、數據表中的數據增加、修改、刪除的同時需要去動態維護索引表,降低了數據的維護速度

二、索引的分類

1、唯一索引:表上一個字段或者多個字段的組合建立的索引,這些字段組合起來能夠確定唯一,允許存在空值(只允許存在一條空值)
2、非唯一索引:表上一個字段或者多個字段的組合建立的索引,可以重複,不需要唯一
3、主鍵索引:(主索引)根據主鍵pk_clolum(length)建立索引,不允許重複,不允許空值;
4、聚合索引:表中記錄的物理順序與鍵值的索引順序相同
5、非聚合索引:表中記錄的物理順序與鍵值的索引順序無關
6、全文索引:在某個字段設置全文索引後,根據特定語法查找滿足條件的字段;

1、全文搜索在 MySQL 中是一個 FULLTEXT 類型索引。FULLTEXT 索引在 MySQL 5.6 版本之後支持 InnoDB,而之前的版本只支持 MyISAM 表。
2、目前只有char、varchar,text 列上可以創建全文索引。
3、 like “value%” 可以使用索引,但是對於 like “%value%” 這樣的方式,執行全表查詢

7、普通索引:用表中的普通列構建的索引,沒有任何限制
8、組合索引:用多個列組合 構建的索引,但是在使用過程中有諸多規則,遵循最左前綴原則,順序至關重要
9、Hash索引(Memory存儲引擎)是通過索引列的值計算出hashCode,之後在相應的物理位置存取索引列的值,由於hashCode的唯一性,因此Hash索引不能進行範圍查找或者是順序查找。

三、B樹-數據庫索引原理

轉載自博客:https://blog.csdn.net/endlu/article/details/51720299
2019.8.26補充:https://www.cnblogs.com/nullzx/p/8729425.html(關於B樹與b+樹更通俗)

1、B樹(平衡多路查找樹)

特性:
關鍵字個數 = 兒子節點個數-1、每一個關鍵字按照升序排序、非葉子結點也存儲數據、根節點至少2個子女,非葉結點至少ceil(m/2)個子女

  • 樹中每個結點最多含有m個孩子(m>=2);
  • 除根結點和葉子結點外,其它每個結點至少有[ceil(m / 2)]個孩子(其中ceil(x)是一個取上限的函數);
  • 若根結點不是葉子結點,則至少有2個孩子(特殊情況:沒有孩子的根結點,即根結點爲葉子結點,整棵樹只有一個根節點);
  • 所有葉子結點都出現在同一層,葉子結點不包含任何關鍵字信息(可以看做是外部接點或查詢失敗的接點,實際上這些結點不存在,指向這些結點的指針都爲null);
  • 每個非終端結點中包含有n個關鍵字信息: (P1,K1,P2,K2,P3,…,Kn,Pn+1)。其中:
    a) Ki (i=1…n)爲關鍵字,且關鍵字按順序升序排序K(i-1)< Ki。
    b) Pi爲指向子樹根的接點,且指針P(i)指向子樹種所有結點的關鍵字均小於Ki,但都大於K(i-1)。
    c) 關鍵字的個數n必須滿足: [ceil(m / 2)-1]<= n <= m-1。

在這裏插入圖片描述

2、B樹插入刪除

實例引用:https://www.cnblogs.com/nullzx/p/8729425.html

2.1、插入

1)根據要插入的key的值,找到葉子結點並插入。
2)判斷當前結點key的個數是否小於等於m-1,若滿足則結束,否則進行第3步。
3)以結點中間的key爲中心分裂成左右兩部分,然後將這個中間的key插入到父結點中,這個key的左子樹指向分裂後的左半部分,這個key的右子支指向分裂後的右半部分,然後將當前結點指向父結點,繼續進行第3步。(核心思想:找到中間值,提升爲父節點,之後分裂爲左右)

2.2、刪除

1 ) 找到下一個記錄,之後用下一個記錄代替當前記錄的位置
2 ) 當前節點個數大於ceil(m/2)-1,直接刪除
3 ) 當前節點個數大於ceil(m/2)-1,跟兄弟節點借一個,前提是兄弟節點個數大於ceil(m/2)-1,兄弟節點借的節點上移,父節點ke下移
4 )兄弟節點個數小於等於ceil(m/2)-1,父節點下移之後與兄弟節點合併

3、B+樹

實例引用:https://www.cnblogs.com/nullzx/p/8729425.html

B+樹特有:
1.有n棵子樹的結點中含有n個關鍵字; (而B樹是n棵子樹有n-1個關鍵字)
2.所有的葉子結點中包含了全部關鍵字的信息,及指向含有這些關鍵字記錄的指針,且葉子結點本身依關鍵字的大小自小而大的順序鏈接。(而B樹的葉子節點並沒有包括全部需要查找的信息)
3.所有的非終端結點可以看成是索引部分,結點中僅含有其子樹根結點中最大(或最小)關鍵字。 (而B 樹的非終節點也包含需要查找的有效信息)
4.關鍵字按照從小到大的順序排列

在這裏插入圖片描述

3.1 B+樹插入

  1. 根節點,直接插入就可以了
  2. 葉子結點:由於在B+樹中葉子結點實際保存了了數據,因此在插入B+樹後如果當前節點小於m-1,直接插入;否則就將當前節點分解,左葉子結點包含前ceil(m/2)個,後ceil(m/2)+1記錄到右節點,將ceil(m/2)記錄的key進到父節點(父節爲索引類型)
  3. 索引節點:若當前結點key的個數小於等於m-1,則插入結束。否則,分裂左右,左前(m-1)/2個節點,右爲後邊的節點,之後選擇(m-1)/2插入到父節點

3.2 B+樹刪除

4、B+樹的優勢

1、查找:B+樹磁盤讀寫次數更低
因爲B+樹非葉子結點只是相當於一個索引,會將所有關鍵字具體信息都存儲葉子結點,也就導致B+樹能夠存儲更加多的關鍵字數量,構造的樹更加矮胖,一次性讀入內存的關鍵字數量增加,IO讀寫次數減少

1、 在索引查找的時候,B樹的搜索方式是首先找到一個搜索下界,也就是滿足條件的最低值,之後通過中序遍歷的方式查找,而B+樹在查找到搜索下界後,直接通過鏈指針開始查找關鍵字信息
2、範圍查找:B樹從二叉樹的下限一直中序遍歷,知道查找到二叉樹的上線,而B+樹知道二叉樹下限後,直接鏈表查找
2、B+tree的查詢效率更加穩定
由於非終結點不存儲數據,而只是葉子結點中關鍵字的索引。所以任何關鍵字的查找必須走一條從根結點到葉子結點的路。所有關鍵字查詢的路徑長度相同,導致每一個數據的查詢效率相當。

5、B樹與B+樹的差別

引用自:https://blog.csdn.net/q936889811/article/details/79780307
1、B樹的同一鍵不會出現多次,可能在葉子節點上也可能在非葉子節點上; b+樹的鍵一定會出現在葉子節點上,同時也可能在非葉子節點上重複出現。
簡單的說,b+樹的非葉子節點存儲的都是鍵值,鍵值對應的具體數據都存儲在葉子節點上。
2、b數據的每個節點存儲的是真是數據,會導致每個節點的存儲的數據量變小,所以整個b樹的高度會相對變高。隨着數據量的變大,維護代價也增加; b+樹的非葉子節點只存儲的是鍵值,相對而言,一個非葉子節點存儲的記錄個數要比b樹多的多。
3、b+樹是橫向擴展,隨着數據增加,會變成一個矮胖子,b樹是縱向擴展,最終樹的高度越來越高(高瘦子)。
4、b樹的查詢效率與鍵在b樹的位置有關係,在葉子及誒單的時候最大複雜度與b+樹相同;b+樹複雜度對某個建成的樹是固定的
5、 b樹的鍵的位置不固定並且整個樹結構中只出現一次,增刪改查操作複雜度逐漸加;b+樹中非葉子節點對於葉子節點來說就像一個索引,增刪改的時候只要找到鍵值(索引)的位置,再一層層的向下找即可,只有在遇到一個節點存儲滿了會對b+樹分裂。
6、 b樹種所有的數據都只存儲一份;b+樹除存儲了所有數據的葉子節點外,還有之存儲鍵值數據的非葉子節點。所以,b+樹比b樹會多佔存儲空間,多佔的空間就是b+樹的非葉子節點的所有空間。

四、聚合索引與非聚合索引

在這裏插入圖片描述

聚合索引與非聚合索引是一種存儲方式,而不是一種單獨的索引類型

前提概念:
1、按照索引的鍵是否爲主鍵來分爲“主索引”和“輔助索引”,使用主鍵鍵值建立的索引稱爲“主索引”,其它的稱爲“輔助索引”
2、聚簇索引的輔助索引的葉子節點的data存儲的是主鍵的值,主索引的葉子節點的data存儲的是數據本身,也就是說數據和索引存儲在一起,並且索引查詢到的地方就是數據(data)本身,那麼索引的順序和數據本身的順序就是相同的;
而非聚簇索引的主索引和輔助索引的葉子節點的data都是存儲的數據的物理地址,也就是說索引和數據並不是存儲在一起的,數據的順序和索引的順序並沒有任何關係,也就是索引順序與數據物理排列順序無關。
3、兩者相同點就是通過B+樹結構來構造B樹索引

1、聚合索引(InnoDB存儲引擎需要)

定義:數據行的物理順序與列值(一般是主鍵的那一列)的邏輯順序相同,一個表中只能擁有一個聚集索引。

1、選擇B+樹作爲存儲結構
2、聚合索引必須有主鍵,沒有主鍵就會選擇Unique key作爲主鍵,沒有Unique則會在系統內部生成rowid作爲主鍵,因此主鍵不宜過長,使得輔助索引過大,主鍵如果不是單調的就會造成B+Tree頻繁的分裂調整
3、在InnoDb上會選擇自增字段作爲主鍵,是爲了維持B+樹的分裂特性,順序添加到當前索引的後續位置,當達到最大就會分裂產生新的頁,也不需要移動原有的順序
4、聚合索引主索引和輔助索引,主索引葉子結點存儲鍵值對應的數據本身輔助索引葉子結點存儲主鍵鍵值
5、由於輔助索引存儲的是主鍵鍵值,因此按照輔助索引搜索的時候需要檢索兩遍,第一遍找到對應的主鍵,第二遍在主索引到達葉子結點中找到數據

2、非聚合索引(MyIsam)

定義:該索引中索引的邏輯順序與磁盤上行的物理存儲順序不同,一個表中可以擁有多個非聚集索引。

1、選擇B+樹作爲存儲結構
2、非聚合索引有主索引和輔助索引(兩個索引幾乎一樣),但是主索引不允許爲空,現在就需要考慮在索引分類中介紹的非聚合索引的概念,由於物理順序與索引順序不同,因此每一個葉子節點存儲的是指向鍵值對應的數據的物理地址(數據記錄的地址)
3、非聚簇索引的數據表和索引表是分開存儲的
4、獲取數據的方式是首先根據B+樹獲取索引,取出對應數據記錄的地址,之後再去讀取相應的數據記錄
5、只有在MyISAM中才能使用FULLTEXT索引。(mysql5.6以後innoDB也支持全文索引)
6、輔助索引的意義:如果給出的查詢條件不是主鍵,此時就使用輔助索引,並且使用輔助索引不需要使用主索引

1、使用聚合索引的場景:

  • 某列包含小數目的不同值
  • 排序和範圍索引(主鍵遞增)
    2、使用非聚合索引的場景:
  • 某列包含大數目的不同值(因爲在葉子節點不需要去保存數據,只需要保存地址)
  • 頻繁更新的列,因爲非聚集索引添加記錄時,不會引起數據順序的重組

3、InNoDB與MyISAM異同

博客(自己還未閱讀):https://www.cnblogs.com/y-rong/p/8110596.html

1、InnoDB 支持事務,支持行級別鎖定,支持 B-tree、Full-text (InNoDB從1.2.X版本開始支持全文搜索的技術)等索引,不支持 Hash 索引,但是給了又有一個特殊的解釋:InnoDB存儲引擎 是支持hash索引的,不過,我們必須啓用,hash索引的創建由InnoDB存儲引擎引擎自動優化創建,是數據庫自身創建並使用,DBA(數據庫管理員)無法干預;
2、MyISAM 不支持事務,支持表級別鎖定,支持 B-tree、Full-text 等索引,不支持 Hash 索引;
3、Memory 不支持事務,支持表級別鎖定,支持 B-tree、Hash 等索引,不支持 Full-text 索引;
4、MyISAM引擎不支持外鍵,InnoDB支持外鍵
5、MyISAM引擎的表在大量高併發的讀寫下會經常出現表損壞的情況
6、對於count()查詢來說MyISAM更有優勢,MyISAM直接通過計數器獲取。InnoDB需要通過掃描全部數據,雖然InNoDB存儲引擎是支持行級別所,InNoDB是行級別鎖,是where對他主鍵是有效,非主鍵的都會鎖全表的
7、MyISAM引擎的表的查詢、更新、插入的效率要比InnoDB高,如果你的數據量是百萬級別的,並且沒有任何的事務處理,那麼用MyISAM是性能最好的選擇。並且MyISAM可以節省很多內存,因爲MyISAM索引文件是與數據文件分開放置,並且索引是有壓縮,內存使用率提高不少
8、平臺承載的大部分項目是讀多寫少的項目,MyISAM讀性能比InNoDB強很多

4、InNoDB存儲引擎內幕略讀

1、版本功能

在這裏插入圖片描述

2、關鍵特性

(1)插入緩存:正常插入自增ID速度非常快,但是如果使用UUID(防止注入式攻擊,當我們使用主鍵自增的時候,需要刪除一個東西的時候,一般都是id=?。這樣的話我就可以在url中修改這個id的值,這樣可能就被人刪除了其他東西,UUID這個就是給主鍵id加上一層鎖,使它不暴露給用戶)者中隨機插入(非連續)的值,此時需要離散的訪問非聚集索引頁,不是直接插入索引頁,而是判斷非索引也是否在緩衝池中,若在,則直接插入,若沒在則放入Insert Buffer中,在Insert Buffer 中合併後插入到索引頁,提高了插入性能

InsertBuffer使用條件

  1. 索引是輔助索引
    2、索引不是唯一的

(2)兩次寫
避免在處理事務時候發生宕機,雖然說事務操作可以日誌恢復,但是如果宕機的時候完全刪除當前頁,如果,doubleWrite,一部分爲內存中doublewrite buffer ,大小爲2M,另一部分物理磁盤表空間中連續的128個頁。緩衝池的髒頁刷新的時候,首先會刷新到doublewrite buffer中,之後纔會寫入到各個表空間文件,遇到宕機,只需要從共享空間doublewrite中找到該頁的副本恢復,之後重做日誌
(3)自適應hash索引
InNoDB會監控對錶上的各索引頁查詢,如果觀察到建立hash索引可以帶來速度提升,則建立hash索引,自動根據訪問評率和模式來自動爲某些熱點也建立索引
(4)異步io
AIO可以將多個IO請求進行IO Merge,當一個IO請求發出後,可以立即發出另一個IO請求,當所有IO請求發送完畢,等待IO操作完成

3、全文索引

使用倒排索引來實現,兩種表現形式:
(1)inverted file index{單詞,所在文檔id}
(2)full inverted index{單詞,( 單詞所在文檔,在具體文檔中的位置)}

4、鎖

1、Recored Lock:當個行記錄上鎖
2、Gap Lock:間隙鎖,鎖定一個範圍,但不包含記錄本身
3.Next-Key Lock:鎖定一個範圍,並且鎖定記錄本身
4、InNoDB存儲影青通過通過Next-Key Locking 來避免幻讀問題

五、組合索引(覆蓋索引)

基於多個字段創建的索引就是組合索引。

組合索引規則:
1、最左原則:索引是key index (a,b,c). 可以支持a | a,b| a,b,c 3種組合進行查找,但不支持 b,c進行查找 .當最左側字段是常量引用時,索引就十分有效。(電話簿中利用姓名查找人,姓和名分別是不同的列,知道姓電話簿有用,知道姓知道名電話簿有用,知道名不知道姓電話簿無用)

補充:
key_len:EXPLAIN執行計劃中有一列 key_len用於表示本次查詢中,所選擇的索引長度有多少字節,通常我們可藉此判斷聯合索引有多少列被選擇了。

1、index Key:索引數據範圍

  • 下邊界
    MySQL利用=、>=、> 來確定下邊界(first key),利用最左原則,首先判斷第一個索引鍵值在where條件中是否存在,如果存在,則判斷比較符號,如果爲(=,>=)中的一種,加入下邊界的界定,然後繼續判斷下一個索引鍵,如果存在且是(>),則將該鍵值加入到下邊界的界定,停止匹配下一個索引鍵;如果不存在,直接停止下邊界匹配。
  • 上邊界
    上邊界(last key)和下邊界(first key)類似,首先判斷是否是否是(=,<=)中的一種,如果是,加入界定,繼續下一個索引鍵值匹配,如果是(<),加入界定,停止匹配

2、Index Filter :用於過濾索引查詢範圍中不滿足查詢條件的記錄

Index Filter的提取規則:同樣從索引列的第一列開始,檢查其在where條件中是否存在:若存在並且where條件僅爲 =,則跳過第一列繼續檢查索引下一列,下一索引列採取與索引第一列同樣的提取規則;若where條件爲 >=、>、<、<= 其中的幾種,則跳過索引第一列,將其餘where條件中索引相關列全部加入到Index Filter之中;若索引第一列的where條件包含 =、>=、>、<、<= 之外的條件,則將此條件以及其餘where條件中索引相關列全部加入到Index Filter之中;若第一列不包含查詢條件,則將所有索引相關條件均加入到Index Filter之中。

以上index Key和Index Filter都是通過索引列來實現的,而Table Filter是針對非索引列

3、Table Filter :無法使用索引過濾,使用表過濾

提取規則:所有不屬於索引列的查詢條件,均歸爲Table Filter之中。

where索引過程:

圖片轉載自:http://www.fordba.com/spend-10-min-to-understand-how-mysql-use-index.html

在這裏插入圖片描述

六、索引失效

1、在where後使用or,導致索引失效(儘量少用or)
2、使用like ,like查詢是以%開頭,以%結尾不會失效
3、不符合最左原則
4、如果列類型是字符串,那一定要在條件中將數據使用引號引用起來,否則不使用索引
5、 使用in導致索引失效
6、使用mysql內部函數導致索引失效,可能會導致索引失效。
7、如果MySQL估計使用索引比全表掃描更慢,則不使用索引

七、索引Demo

CREATE TABLE table_name[col_name data type] [unique|fulltext][index|key][index_name](col_name[length])[asc|desc]
  • unique|fulltext爲可選參數,分別表示唯一索引、全文索引
  • index和key爲同義詞,兩者作用相同,用來指定創建索引
  • col_name爲需要創建索引的字段列,該列必須從數據表中該定義的多個列中選擇
  • index_name指定索引的名稱,爲可選參數,如果不指定,默認col_name爲索引值
  • length爲可選參數,表示索引的長度,只有字符串類型的字段才能指定索引長度
  • asc或desc指定升序或降序的索引值存儲
  • 創建數據庫並添加數據
CREATE TABLE `students` (
  `stud_id` int(11) NOT NULL,
  `name` varchar(50) NOT NULL,
  `email` varchar(50) NOT NULL,
  `phone` varchar(30) NOT NULL,
  `create_date` date DEFAULT NULL,
  `content` text NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
INSERT INTO `students` (`stud_id`, `name`, `email`, `phone`, `create_date`, `content`) VALUES
(1, 'admin', '[email protected]', '18729902095', '1983-06-25', 'i am robin'),
(2, 'root', '[email protected]', '2', '1983-12-25', 'i am xiaoluo'),
(3, '110', '[email protected]', '3dsad', '2017-04-28', 'i am lili');

1、創建普通索引

  • 查看索引show INDEX from students
  • 創建索引方式

1.直接創建:CREATE INDEX index_name ON student(name);
2、修改表結構方式創建索引:alter TABLE students ADD INDEX index_name2(name);
3、創建表的時候建立索引:添加:index index_name3(name)
創建後的索引:
在這裏插入圖片描述
查看是否通過索引能夠獲取數據:EXPLAIN SELECT name FROMstudentsWHERE name='admin'
通過索引獲取數據:
在這裏插入圖片描述

-刪除索引: DROP INDEX index_name ON table_name;
                    alter table表名drop index 索引名;

2、創建唯一索引(Index前邊添加unique)

1、創建郵箱索引:

CREATE UNIQUE INDEX index_email on students(email);
ALTER TABLE students ADD UNIQUE INDEX index_mail2(email);
創建表的時候添加:UNIQUE index_name_unique(email);

3、創建主鍵索引

主鍵索引是一種特殊的唯一索引,一個表只能有一個主鍵,不允許有空值。一般是在建表的時候同時創建主鍵索引:
1、創建郵箱索引:

ALTER TABLE students ADD PRIMARY KEY(stud_id);
創建表的時候添加:primary key(‘stud_id’)

4、創建全文索引

1、創建全文索引
創建表的時候添加:fulltext(content)
CREATE FULLTEXT INDEX index_content on students(content);
ALTER table students ADD FULLTEXT INDEX index_content2(content);
2、show index from students;
在這裏插入圖片描述
3、全文索引查詢:

SELECT * FROM `students` WHERE MATCH(`content`) against('robin')

在這裏插入圖片描述
4、建立一個聯合索引
添加另外一個全文索引:ALTER TABLE students ADD FULLTEXT INDEX email_content(email,content);
聯合全文索引:SELECT * FROMstudentsWHERE MATCH(email,content) against('student robin')
在這裏插入圖片描述

八、引用博客

【1】實戰demo:https://blog.csdn.net/u010648555/article/details/81102957
【2】B樹與B+樹:https://blog.csdn.net/endlu/article/details/51720299
【3】聚合索引與非聚合索引概念:https://blog.csdn.net/tongdanping/article/details/79878302
【4】InNoDB與MyISAM差別:https://www.cnblogs.com/y-rong/p/8110596.html
【5】組合索引:http://www.fordba.com/spend-10-min-to-understand-how-mysql-use-index.html
【6】Mysql如何利用索引,通過組合索引:http://hedengcheng.com/?p=577
圖片:http://www.fordba.com/spend-10-min-to-understand-how-mysql-use-index.html
【7】索引使用規則;https://www.cnblogs.com/duanxz/p/5244703.html

發佈了48 篇原創文章 · 獲贊 25 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章