MySQL表爲什麼必須有主鍵 -- 聚集索引的簡單介紹

注意:下面討論的都是MySQL5.6版本中的innodb引擎。

比較規範的數據庫表設計(包括我們公司)都會有一條不成文的規定,那就是給每張表一個自增主鍵。那麼自增主鍵除了有數據的唯一性外,還有什麼所用呢?爲什麼要有自增主鍵?

之前我轉發的《58到家數據庫30條軍規解讀》中解釋道:

  • 主鍵遞增,數據行寫入可以提高插入性能,可以避免page分裂,減少表碎片提升空間和內存的使用
  • 主鍵要選擇較短的數據類型, Innodb引擎普通索引都會保存主鍵的值,較短的數據類型可以有效的減少索引的磁盤空間,提高索引的緩存效率
  • 無主鍵的表刪除,在row模式的主從架構,會導致備庫夯住

第三條先不必關注,我們來看看前兩條。 
爲什麼能提高插入性能呢,避免page分頁又是怎麼回事?

這裏就不得不說一下聚集索引了。


聚集索引(Clustered Index)

一個聚集索引定義了表中數據的物理存儲順序。如何理解聚集索引呢,好比一個電話本,比如一個電話本是按照姓氏排序,並且電話號碼緊跟着後面。因爲聚集索引決定了表中數據的物理存儲順序,那麼一個表則有且只有一個聚集索引。一個聚集索引可以包含多個列。好比一個電話本是基於名字,姓氏同時排序。

Innodb的聚集索引

Innodb的存儲索引是基於B+tree,理所當然,聚集索引也是基於B+tree。與非聚集索引的區別則是,聚集索引既存儲了索引,也存儲了行值。當一個表有一個聚集索引,它的數據是存儲在索引的葉子頁(leaf pages)。因此innodb也能理解爲基於索引的表。

* 那麼Innodb如何決定那個索引作爲聚集索引呢?*


Innodb如何選擇一個聚集索引

對於Innodb,主鍵毫無疑問是一個聚集索引。但是當一個表沒有主鍵,或者沒有一個索引,Innodb會如何處理呢。請看如下規則

如果一個主鍵被定義了,那麼這個主鍵就是作爲聚集索引

如果沒有主鍵被定義,那麼該表的第一個唯一非空索引被作爲聚集索引

如果沒有主鍵也沒有合適的唯一索引,那麼innodb內部會生成一個隱藏的主鍵作爲聚集索引,這個隱藏的主鍵是一個6個字節的列,改列的值會隨着數據的插入自增。

還有一個需要注意的是:

次級索引的葉子節點並不存儲行數據的物理地址。而是存儲的該行的主鍵值。

所以:一次級索引包含了兩次查找。一次是查找次級索引自身。然後查找主鍵(聚集索引)


現在應該明白了吧,建立自增主鍵的原因是:

Innodb中的每張表都會有一個聚集索引,而聚集索引又是以物理磁盤順序來存儲的,自增主鍵會把數據自動向後插入,避免了插入過程中的聚集索引排序問題。聚集索引的排序,必然會帶來大範圍的數據的物理移動,這裏面帶來的磁盤IO性能損耗是非常大的。 
而如果聚集索引上的值可以改動的話,那麼也會觸發物理磁盤上的移動,於是就可能出現page分裂,表碎片橫生。

解讀中的第二點相信看了上面關於聚集索引的解釋後就很清楚了。


雖然遵循上面的原則也沒錯,但某些特殊的情況也是可以自己指定一些非自增主鍵爲聚集索引的。如:

  • 當數據量大,但長時間不會被更新的;
  • 新生成的數據的索引本來就是按照自增的順序增加的等等。

舉個栗子,(只是栗子啊,現實中不太可能): 
有一家公司裏的員工上百萬,有關員工的個人信息幾年都不會發生變化,那麼以員工的user_id號來作爲各個表的索引就很適合。因爲一個員工的信息都按照物理順序呢排列在一起了,避免了磁盤移動查找數據的IO時間。比如說員工屬於幾個部門,一下子就查到了,不同分不同的地址去挨個進行磁盤掃描。

栗子從簡,哈哈哈哈,就這樣子吧,我也不太會寫,簡單的記錄下來了~

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