myisam
引擎使用
b+tree
作為索引結構,葉節點的
data
域存放的是資料記錄的位址。下圖是
myisam
索引的原理圖:
這裡設表一共有三列,假設我們以
col1
為主鍵,則上圖是乙個
myisam
表的主索引(
primary key
)示意。可以看出
myisam
的索引檔案僅僅儲存資料記錄的位址。在
myisam
中,主索引和輔助索引(
secondary key
)在結構上沒有任何區別,只是主索引要求
key是唯一的,而輔助索引的
key可以重複。如果我們在
col2
上建立乙個輔助索引,則此索引的結構如下圖所示:
同樣也是一顆
b+tree
,data
域儲存資料記錄的位址。因此,
myisam
中索引檢索的演算法為首先按照
b+tree
搜尋演算法搜尋索引,如果指定的
key存在,則取出其
data
域的值,然後以
data
域的值為位址,讀取相應資料記錄。
myisam
的索引方式也叫做
「非聚集
」的,之所以這麼稱呼是為了與
innodb
的聚集索引區分。 雖然
innodb
也使用b+tree
作為索引結構,但具體實現方式卻與
myisam
截然不同。
第乙個重大區別是
innodb
的資料檔案本身就是索引檔案。從上文知道,
myisam
索引檔案和資料檔案是分離的,索引檔案僅儲存資料記錄的位址。而在
innodb
中,表資料檔案本身就是按
b+tree
組織的乙個索引結構,這棵樹的葉節點
data
域儲存了完整的資料記錄。這個索引的
key是資料表的主鍵,因此
innodb
表資料檔案本身就是主索引。
下圖是innodb
主索引(同時也是資料檔案)的示意圖,可以看到葉節點包含了完整的資料記錄。這種索引叫做聚集索引。因為
innodb
的資料檔案本身要按主鍵聚集,所以
innodb
要求表必須有主鍵(
myisam
可以沒有),如果沒有顯式指定,則
mysql
系統會自動選擇乙個可以唯一標識資料記錄的列作為主鍵,如果不存在這種列,則
mysql
自動為innodb
表生成乙個隱含字段作為主鍵,這個字段長度為
6個位元組,型別為長整形。
第二個與
myisam
索引的不同是
innodb
的輔助索引
data
域儲存相應記錄主鍵的值而不是位址。換句話說,
innodb
的所有輔助索引都引用主鍵作為
data
域。例如,下圖為定義在
col3
上的乙個輔助索引:
這裡以英文本元的
ascii
碼作為比較準則。聚集索引這種實現方式使得按主鍵的搜尋十分高效,但是輔助索引搜尋需要檢索兩遍索引:首先檢索輔助索引獲得主鍵,然後用主鍵到主索引中檢索獲得記錄。
了解不同儲存引擎的索引實現方式對於正確使用和優化索引都非常有幫助,例如知道了
innodb
的索引實現後,就很容易明白為什麼不建議使用過長的字段作為主鍵,因為所有輔助索引都引用主索引,過長的主索引會令輔助索引變得過大。再例如,用非單調的字段作為主鍵在
innodb
中不是個好主意,因為
innodb
資料檔案本身是一顆
b+tree
,非單調的主鍵會造成在插入新記錄時資料檔案為了維持
b+tree
的特性而頻繁的**調整,十分低效,而使用自增字段作為主鍵則是乙個很好的選擇。
mysql
的優化主要分為結構優化(
schemeoptimization
)和查詢優化(
query optimization)。
實際上一旦理解了索引背後的機制,那麼選擇高效能的策略就變成了純粹的推理,並且可以理解這些策略背後的邏輯。
在使用innodb
儲存引擎時,如果沒有特別的需要,請永遠使用乙個與業務無關的自增欄位作為主鍵
經常看到有帖子或部落格討論主鍵選擇問題,有人建議使用業務無關的自增主鍵,有人覺得沒有必要,完全可以使用如學號或身份證號這種唯一字段作為主鍵。不論支援哪種論點,大多數論據都是業務層面的。如果從資料庫索引優化角度看,使用
innodb
引擎而不使用自增主鍵絕對是乙個糟糕的主意
上文討論過
innodb
的索引實現,
innodb
使用聚集索引,資料記錄本身被存於主索引(一顆
b+tree
)的葉子節點上。這就要求同乙個葉子節點內(大小為乙個記憶體頁或磁碟頁)的各條資料記錄按主鍵順序存放,因此每當有一條新的記錄插入時,
mysql
會根據其主鍵將其插入適當的節點和位置,如果頁面達到裝載因子(
innodb
預設為15/16
),則開闢乙個新的頁(節點)。
如果表使用自增主鍵,那麼每次插入新的記錄,記錄就會順序新增到當前索引節點的後續位置,當一頁寫滿,就會自動開闢乙個新的頁。如下圖所示:
這樣就會形成乙個緊湊的索引結構,近似順序填滿。由於每次插入時也不需要移動已有資料,因此效率很高,也不會增加很多開銷在維護索引上。
如果使用非自增主鍵(如果身份證號或學號等),由於每次插入主鍵的值近似於隨機,因此每次新紀錄都要被插到現有索引頁得中間某個位置:
不得不為了將新記錄插到合適位置而移動資料,甚至目標頁面可能已經被回寫到磁碟上而從快取中清掉,此時又要從磁碟上讀回來,這增加了很多開銷,同時頻繁的移動、分頁操作造成了大量的碎片,得到了不夠緊湊的索引結構,後續不得不通過
optimize table
來重建表並優化填充頁面。
因此,只要可以,請盡量在
innodb
上採用自增字段做主鍵。
MySQL索引原理之索引原理
索引定義 是儲存引擎用於快速查詢記錄的一種資料結構。需要額外開闢空間和資料維護工作。索引是物理資料頁儲存,在資料檔案中 innodb,ibd檔案 利用資料頁 page 儲存。索引可以加快檢索速度,但是同時也會降低增刪改操作速度,索引維護需要代價。索引涉及的理論知識 二分查詢法 hash和b tree...
MySQL優化系列2 索引原理和優化
索引是為了加速對錶中資料行的檢索而建立的一種分散儲存的資料結構 索引能極大的減少儲存引擎需要掃瞄的資料量 索引可以把隨機io變為順序io 索引可以幫助我們在進行分組 排序等操作時,避免使用臨時表 為了說明索引的資料結構,先對比一下幾種常見的資料結構特點 在二叉樹中,左子樹的鍵值總是小於根的鍵值,右子...
MySQL 索引與索引原理
本人菜鳥一枚,如有理解不對,請大神多多指正!一 索引 1 什麼是索引?答 索引類似於一本書的目錄,便於資料快速高效的查詢,也可以解釋為資料按照某個特定的規則去儲存排序資料 2 索引的型別?答 索引可以分為 普通索引,唯一索引,主鍵索引和組合索引 2.1 普通索引 最基本的一種索引方式,沒有什麼限制 ...