54、數據庫索引
索引的優缺點
??優點:
??1、大大加快數據的檢索速度;
??2、創建唯一性索引,保證數據庫表中每一行數據的唯一性;
??3、加速表和表之間的連接;
??4、在使用分組和排序子句進行數據檢索時,可以顯著減少查詢中分組和排序的時間。
??缺點:
??1、索引需要占物理空間;
??2、當對表中的數據進行增加、刪除和修改的時候,索引也要動態的維護,降低數據的維護速度。
索引的分類
??1、唯一索引: 是在表上一個或者多個字段組合建立的索引,這個或者這些字段的值組合起來在表中不可以重復。
??2、非唯一索引:是在表上一個或者多個字段組合建立的索引,這個或者這些字段的值組合起來在表中可以重復,不要求唯一。
??3、主鍵索引(主索引): 是唯一索引的特定類型。表中創建主鍵時自動創建的索引,一個表只能建立一個主索引。
??4、聚集索引(聚簇索引、Innodb):表中記錄的物理順序與鍵值的索引順序相同。 因為真實數據的物理順序只有一種,所以一個表只能有一個聚集索引。葉子節點(B+樹)存儲真實的數據行,不再有另外單獨的數據頁。
??5、非聚集索引(Mylsam):表中記錄的物理順序與鍵值的索引順序不同。這也是非聚集索引與聚集索引的根本區別。葉子節點并非數據節點,而是每一個指向真正數據行的指針。
??聚集索引與非聚集索引的區別:
??1)、聚集索引的優缺點:優點是查詢速度快,因為一旦具有第一個索引值的記錄被找到,具有連續索引值的記錄也一定物理的緊跟其后。缺點是對表進行修改速度較慢,這是為了保持表中的記錄的物理順序與索引順序的一致,而把記錄插入到數據頁的相應位置,必須在數據頁中進行數據重排,降低了執行速度。在插入新記錄時數據文件為了維持 B+Tree 的特性而頻繁的分裂調整,十分低效。
??建議使用聚集索引的場合為:A.某列包含了小數目的不同值。B.排序和范圍查找。
??2)、聚集索引和非聚集索引都采用了B+樹的結構,但非聚集索引的葉子層并不與實際的數據頁相重疊,而采用葉子層包含一個指向表中的記錄在數據頁中的指針的方式。聚集索引的葉節點就是數據節點,而非聚集索引的葉節點仍然是索引節點。
??3)、非聚集索引添加記錄時,不會引起數據順序的重組。
??看上去聚簇索引的效率明顯要低于非聚簇索引,因為每次使用輔助索引檢索都要經過兩次 B+樹查找,這不是多此一舉嗎?聚簇索引的優勢在哪?
??1)、由于行數據和葉子節點存儲在一起,這樣主鍵和行數據是一起被載入內存的,找到葉子節點就可以立刻將行數據返回了,如果按照主鍵 Id 來組織數據,獲得數據更快。
??2)、輔助索引使用主鍵作為"指針",而不是使用地址值作為指針的好處是,減少了當出現行移動或者數據頁分裂時,輔助索引的維護工作,InnoDB 在移動行時無須更新輔助索引中的這個"指針"。也就是說行的位置會隨著數據庫里數據的修改而發生變化,使用聚簇鍵索引就可以保證不管這個主鍵 B+ 樹的節點如何變化,輔助索引樹都不受影響。
??6、組合索引: 基于多個字段而創建的索引就稱為組合索引,組合索引的使用要遵從最左前綴。在最左前綴原則中,范圍查詢會導致組合索引半生效,where子句有or出現還是會遍歷全表。
Mysql怎么增加一個索引
??創建索引:create index idx1 on table(col1, col2, col3);
??添加索引:alter table tablename add index indexname(col1, col2);
55、數據庫索引的實現
??目前大部分數據庫系統及文件系統都采用B-Tree(B樹)或其變種B+Tree(B+樹)作為索引結構。B+Tree 是數據庫系統實現索引的首選數據結構。
??在 MySQL 中,索引屬于存儲引擎級別的概念,不同存儲引擎對索引的實現方式是不同的。
MyISAM 索引實現(非聚集索引)
??MyISAM引擎使用B+Tree作為索引結構,葉節點的data域存放的是數據記錄的地址。
??圖8是一個MyISAM表的主索引(Primary Key)示意,可以看出 MyISAM 的索引文件僅僅保存數據記錄的地址。在 MyISAM 中,主索引和輔助索引(Secondary key)在結構上沒有任何區別,只是主索引要求 key 是唯一的,而輔助索引的 key 可以重復。如果我們在 Col2 上建立一個輔助索引,則此索引的結構如下圖所示:
??同樣也是一顆 B+Tree,data 域保存數據記錄的地址。因此,MyISAM 中索引檢索的算法會首先按照 B+Tree 搜索算法搜索索引,如果指定的 Key 存在,則取出其data 域的值,然后以 data 域的值為地址,讀取相應數據記錄。
InnoDB 索引實現(聚集索引)
??MyISAM 索引文件和數據文件是分離的,索引文件僅保存數據記錄的地址。而在InnoDB 中,表數據文件本身就是按 B+Tree 組織的一個索引結構,這棵樹的葉節點data 域保存了完整的數據記錄(第一個重大區別)。 這個索引的 key 是數據表的主鍵,因此 InnoDB 表數據文件本身就是主索引。
??上圖是 InnoDB 主索引(同時也是數據文件)的示意圖,可以看到葉節點包含了完整的數據記錄。這種索引叫做聚集索引。因為 InnoDB 的數據文件本身要按主鍵聚集。
??1、InnoDB 要求表必須有主鍵(MyISAM 可以沒有), 如果沒有顯式指定,則 MySQL系統會自動選擇一個可以唯一標識數據記錄的列作為主鍵,如果不存在這種列,則MySQL 自動為 InnoDB 表生成一個隱含字段作為主鍵,類型為長整形。
??2、盡量在 InnoDB 上采用自增字段做表的主鍵。 因為 InnoDB 數據文件本身是一棵B+Tree,非單調的主鍵會造成在插入新記錄時數據文件為了維持 B+Tree 的特性而頻繁的分裂調整,十分低效,而使用自增字段作為主鍵則是一個很好的選擇。如果表使用自增主鍵,那么每次插入新的記錄,記錄就會順序添加到當前索引節點的后續位置,當一頁寫滿,就會自動開辟一個新的頁。
??這樣就會形成一個緊湊的索引結構,近似順序填滿。由于每次插入時也不需要移動已有數據,因此效率很高,也不會增加很多開銷在維護索引上。
??第二個與 MyISAM 索引的不同是 InnoDB 的輔助索引 data 域存儲相應記錄主鍵的值而不是地址。 換句話說,InnoDB 的所有輔助索引都引用主鍵作為 data 域。
??聚集索引這種實現方式使得按主鍵的搜索十分高效,但是輔助索引搜索需要檢索兩遍索引:首先檢索輔助索引獲得主鍵,然后用主鍵到主索引中檢索獲得記錄。
??引申:為什么不建議使用過長的字段作為主鍵?因為所有輔助索引都引用主索引,過長的主索引會令輔助索引變得過大。
總結
??InnoDB使用的是聚簇索引,將主鍵組織到一棵 B+樹中,而行數據就儲存在葉子節點上,若使用"where id = 14"這樣的條件查找主鍵,則按照 B+樹的檢索算法即可查找到對應的葉節點,之后獲得行數據。若對 Name 列進行條件搜索,則需要兩個步驟:第一步在輔助索引 B+樹中檢索 Name,到達其葉子節點獲取對應的主鍵。第二步使用主鍵在主索引B+樹中再執行一次 B+樹檢索操作,最終到達葉子節點即可獲取整行數據。
??MyISAM 使用的是非聚簇索引,非聚簇索引的兩棵 B+樹看上去沒什么不同,節點的結構完全一致只是存儲的內容不同而已,主鍵索引 B+樹的節點存儲了主鍵,輔助鍵索引B+樹存儲了輔助鍵。表數據存儲在獨立的地方,這兩顆 B+樹的葉子節點都使用一個地址指向真正的表數據,對于表數據來說,這兩個鍵沒有任何差別。由于索引樹是獨立的,通過輔助鍵檢索無需訪問主鍵的索引樹。??
56、為什么使用B+樹作為索引
B/B+ 樹性能分析
??1、n 個節點的平衡二叉樹的高度為 H(即 logn),而 n 個節點的 B/B+樹的高度為logt((n+1)/2)+1;
??2、若要作為內存中的查找表,B 樹卻不一定比平衡二叉樹好,尤其當 m 較大時更是如此。因為查找操作 CPU 的時間在 B-樹上是 O(mlogtn)=O(lgn(m/lgt)),而 m/lgt>1;所以 m較大時O(mlogtn)比平衡二叉樹的操作時間大得多。因此在內存中使用B樹必須取較小的m。(通常取最小值 m=3,此時 B-樹中每個內部結點可以有 2 或 3 個孩子,這種 3 階的 B-樹稱為 2-3 樹)。
為什么說 B+tree比 B 樹更適合實際應用中操作系統的文件索引和數據索引。
??B+tree 的內部節點并沒有指向關鍵字具體信息的指針,因此其內部節點相對 B 樹更小, 如果把所有同一內部節點的關鍵字存放在同一盤塊中,那么盤塊所能容納的關鍵字數量也越多,一次性讀入內存的需要查找的關鍵字也就越多,相對 IO 讀寫次數就降低了。
??由于非終結點并不是最終指向文件內容的結點,而只是葉子結點中關鍵字的索引。所以任何關鍵字的查找必須走一條從根結點到葉子結點的路。所有關鍵字查詢的路徑長度相同,導致每一個數據的查詢效率相當。
??也有人認為數據庫索引采用 B+樹的主要原因是:B 樹在提高了 IO 性能的同時并沒有解決元素遍歷的效率低下的問題,正是為了解決這個問題,B+樹應用而生。B+樹只需要去遍歷葉子節點就可以實現整棵樹的遍歷。而且在數據庫中基于范圍的查詢是非常頻繁的,而 B樹不支持這樣的操作(或者說效率太低,需要中序遍歷)。