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的特性而頻繁的**調整,十分低效,而使用自增字段作為主鍵則是乙個很好的選擇。
上文討論過innodb的索引實現,innodb使用聚集索引,資料記錄本身被存於主索引(一顆b+tree)的葉子節點上。這就要求同乙個葉子節點內(大小為乙個記憶體頁或磁碟頁)的各條資料記錄按主鍵順序存放,因此每當有一條新的記錄插入時,mysql會根據其主鍵將其插入適當的節點和位置,如果頁面達到裝載因子(innodb預設為15/16),則開闢乙個新的頁(節點)。
如果表使用自增主鍵,那麼每次插入新的記錄,記錄就會順序新增到當前索引節點的後續位置,當一頁寫滿,就會自動開闢乙個新的頁。如下圖所示:
這樣就會形成乙個緊湊的索引結構,近似順序填滿。由於每次插入時也不需要移動已有資料,因此效率很高,也不會增加很多開銷在維護索引上。
如果使用非自增主鍵(如果身份證號或學號等),由於每次插入主鍵的值近似於隨機,因此每次新紀錄都要被插到現有索引頁得中間某個位置:
此時mysql不得不為了將新記錄插到合適位置而移動資料,甚至目標頁面可能已經被回寫到磁碟上而從快取中清掉,此時又要從磁碟上讀回來,這增加了很多開銷,同時頻繁的移動、分頁操作造成了大量的碎片,得到了不夠緊湊的索引結構,後續不得不通過optimize table來重建表並優化填充頁面。
因此,只要可以,請盡量在innodb上採用自增字段做主鍵。
為什麼選用自增量作為主鍵索引
myisam引擎使用b tree作為索引結構,葉節點的data域存放的是資料記錄的位址。下圖是myisam索引的原理圖 這裡設表一共有三列,假設我們以col1為主鍵,則上圖是乙個myisam表的主索引 primary key 示意。可以看出myisam的索引檔案僅僅儲存資料記錄的位址。在myisam...
MySQL 為什麼推薦自增 id 作為主鍵
在計算機裡,無論是記憶體還是磁碟,作業系統都是按頁的大小進行讀取的 頁大小通常為 4 kb 磁碟每次讀取都會預讀,會提前將連續的資料讀入記憶體中,這樣就避免了多次 io,這就是計算機中有名的區域性性原理,即我用到一塊資料,很大可能這塊資料附近的資料也會被用到,乾脆一起載入,省得多次 io 拖慢速度,...
uuid和自增 uuid作為主鍵,還是用自增呢?
以預設的innodb儲存引擎為例 做為主鍵時,uuid和自增相比較,自增更適合。原因 1 uuid是無序的,插入資料時,頁的位置會發生變化,頁 速度慢。2 uuid佔的空間大,並且innodb中,別的索引還都要包含主鍵的值,那麼每個索引的空間也都會增大,佔的空間大,需要讀資料時一般會認為需要的io次...