發布日期:Dec 22, 2020

文章於 Jan 10, 2021 更新

Index of Database

索引的目的

為了讓找資料更快。但是這個「更快」是跟誰比較?是跟「沒有索引時從頭逐項查找」相比。

【情境模擬】 假設我們上網徵求「動畫推薦」,得到一些回應像這樣:

18:30 A網友「鋼鍊啦鋼鍊!」

18:45 B網友「有鋼鍊那也要推個銀之匙才行」

19:10 C網友「魔法阿嬤」

19:12 D網友「樂園追放,讚」

20:07 E網友「月刊少女野崎同學,會看到笑死」

21:17 F網友「夏目友人帳~」

所以我們得到了一份原始資料長這樣:

鋼之鍊金術師

銀之匙

魔法阿嬤

樂園追放

月刊少女野崎同學

夏目友人帳

當我們想要找這份動畫推薦清單裡有沒有某部動畫時,

最原始的做法就是從第一個檢查最後一個,這也是資料庫最原始的搜尋資料方式。

如果今天有人問我「樂園追放」這部動畫有沒有在清單裡?

我的印象是「我記得中間有人畫風一變,推了個『魔法阿嬤』,然後後面回答馬上又用『樂園追放』把畫風修回日本動畫了 XD」

這時候就有點帶進了「索引」觀念,因為這次我們不是一筆一筆檢查,而是直接由「魔法阿嬤」切入,找到緊接在後的「樂園追放」。

當清單內容變多時,「直接從某點切入搜索」的速度有很高的機率會比「逐項尋找」快速。

演算法裡的「二元搜尋樹」也是這樣的概念。找資料時從當下的切入點開始兵分兩路,直到找到目標。

「你要找的動畫是『魔法阿嬤』嗎?」 –> 不是

「資料在『魔法阿嬤』之前還是之後?」 –> 之後

「資料在『月刊少女野崎同學』之前還是之後?」 –> 之前

「你要找的動畫是『樂園追放』嗎?」 –> 是

更進一步,我們也可以將資料進行排序,例如將動畫按照出版年份或者作品名字的字數排序,試著加快搜尋的過程,

這就是不同索引方式的演進。

索引的實現

「索引」概念是強烈吃重演算法觀念的領域,「要如何安排資料才能找得更快、耗能更低」正是演算法大展長才之處。 根據索引背後使用的演算法不同,在不同資料情境下可能會產生搜尋速度的落差。

不同資料庫實現「索引」的方式也不盡相同,如果好奇的話需要研究該資料庫的底層設計。

在查詢資料時索引值的用處

舉例有個資料表長這樣,而我們用的資料庫是 MySQL(InnoDB): table_A

column is index ?
id v
name
  • 如果現在搜尋的是索引欄位 SELECT * FROM table_A WHERE id = 3 會用 B+ 樹的概念搜尋
  • 如果現在搜尋的不是索引欄位 SELECT * FROM table_A WHERE name = "Dingo" 跟沒設定索引一樣,只能逐筆找

InnoDB: MySQL 資料庫可以採用的其中一種資料庫引擎,跟 InnoDB 相同作用的還有 MyISAM, MyRocks …… 等。更多資訊可參考 wiki - MySQL資料庫引擎的比較

索引類型

在 InnoDB 中,它有提供的索引基本上分為兩大類 :

  • clustered Index
  • secondary Index
    • 覆蓋索引 ( covering index ) (預設)
      • 內涵:????
    • 連合索引 ( compound index )
      • 內涵:用複數欄位組合成一組索引,建立的順序會影響 index 是否能成功使用以及 WHERE 條件如何下。
    • 前綴索引 ( prefix index )
      • 內涵:????
    • 唯一索引 ( unique index )
      • 內涵:只有這個索引值是具有「必定唯一」的特性,其他種類的索引值都能重複。 unique index 可以做為 clustered Index 的索引值。

關於演算法

  • 二元搜尋樹
    • 每個節點只會有兩個分支
    • 沒有管左右二路的資料數量均等與否
  • B 樹
    • 每個節點容許展開多個分支,分支數量依照建立結構時節點容量設定的大小 & 節點內含的資料而固定。
    • 會主動進行資料分布的平衡,讓各分支所包含的節點與資料盡量左右平衡。
  • B+ 樹
    • 改良的 B 樹
    • 節點的分支數不是固定值,避免頻繁進行結構平衡。
    • 資料永遠在葉節點(不再產生分支的那一層),增加搜尋時間的可預測性。

關於 B-tree & B+ Tree

從進入的節點比大小,分兩路進下一層。下一層的節點會包含已排序的數個值,讓進入第三層的路線變成更多路,每層節點的可容納 key 數有上限,依照 tree 的設計而定(像是每個節點只能放 2~3 個 key 的設計會被稱為 2-3 tree)。

e.g. [find 13!] 7—- 12, 16– 18,23,25 | |- 13,14,15 | |- 8,9,11 | |– 2,5 —- 1 |- 3,4 |- 6

  • a B-Tree is a balanced tree. 他的設計上會讓每個節點盡量平均,數量按照比例分佈。
  • B-Tree 較「二元搜尋樹」有優勢的地方:
    • 不限只能產生兩個分支,可以大幅減少 tree 的高度,提升 Disk I/O 效能
  • B-Tree 改良版:B+ Tree
    • 每個 key 都會在葉節點出現
    • 中間節點的 key 數量更彈性
    • B+ Tree 較「B-Tree」有優勢的地方:
      • 由於 b-tree 的設計不會將節點的 key 都推到同一層,所以每次查詢需要經過的層數不固定
      • 由於 B+ Tree 中間節點的 key 數量更彈性,所以索引增刪時不必頻繁進行平衡工作,增加索引結構的穩定性。

疑問

  • from B+樹
    • 平衡二元搜尋樹 ( Balanced BST )
      • 時間複雜度怎麼判斷?
      • i/o 問題?
        • 關心「硬碟輸入與輸出的時間」的議題。
      • B 樹的設計概念開始看不懂
        • 搞懂了。 :D

參考資料