MySQL 數據表優化設計(五):id 該如何選擇數據類型?

爲 id 列選擇一個好的數據類型非常重要,id 列會經常用於做比較(例如聯合查詢的條件),以及用於查找其他列。而且,id 也經常用於外鍵。因此,id 列的數據類型不僅僅關係自身數據表,也關係到與之關聯的其他數據表。因此,id 用何種數據類型就顯得十分重要。

選擇 id 的數據類型,不僅僅需要考慮數據存儲類型,還需要了解 MySQL 對該種類型如何計算和比較。例如,MySQL 將 ENUM 和 SET 類型在內部使用整型存儲,但是在字符串場景下會當做字符串進行比較。一旦選擇了 id 的數據類型後,需要保證引用 id 的相關數據表的數據類型一致,而且是完全一致,這包括屬性,例如長度、是否有符號!如果混用不同的數據類型可能導致性能問題,即便是沒有性能問題,在進行比較時的隱式數據轉換可能導致難以捉摸的錯誤。而如果在實際開發過程中忘記了數據類型不同這個問題,可能會突然出現意想不到的問題。

在選擇長度的時候,也需要儘可能選擇小的字段長度並給未來留有一定的增長空間。例如,如果是用於存放省份的話,我們只有幾十個值,此時使用 TINYINT 就 INT 就更好,如果是相關的表也存有這個 id 的話,那麼效率差別會很大。

下面是適用於 id 的一些典型的類型:

  • 整型:整型通常來說是最佳的選擇,這是因爲整型的運算和比較都很快,而且還可以設置 AUTO_INCREMENT 屬性自動遞增。
  • ENUM 和 SET:通常不會選擇枚舉和集合作爲 id,然後對於那些包含有“類型”、“狀態”、“性別”這類型的列來說是挺合適的。例如我們需要有一張表存儲下拉菜單時,通常會有一個值和一個名稱,這個時候值使用枚舉作爲主鍵也是可以的。
  • 字符串:儘可能地避免使用字符串作爲 id,一是字符串佔據的空間更大,二是通常會比整型慢。選用字符串作爲 id 時,還需要特別注意 MD5、SHA1和 UUID 這些函數。每個值是在很大範圍的隨機值,沒有次序,這會導致插入和查詢更慢:
    • 插入的時候,由於建立索引是隨機位置(會導致分頁、隨機磁盤訪問和聚集索引碎片),會降低插入速度。
    • 查詢的時候,相鄰的數據行在磁盤或內存上上可能跨度很大,也會導致速度更慢。

如果確實要使用 UUID 值,應當移除掉“-”字符,或者是使用 UNHEX 函數將其轉換爲16字節數字,並使用 BINARY(16)存儲。然後可以使用 HEX 函數以十六進制的方式進行獲取。UUID 產生的方法有很多,有些是隨機分佈的,有些是有序的,但是即便是有序的性能也不如整型。

分佈式 id

對於單體應用來說,id 使用自增或者使用程序直接產生 id 問題都不大,但是如果是對於分佈式應用來說,這種情況可能會導致主鍵衝突錯誤。對於分佈式 id,目前有很多算法,例如有名的雪花(snowflakce)算法,以及國內大廠的一些分佈式 id 開源算法,例如:

分佈式 id 的基本原理是使用機器碼、時間戳加序列號構成。通過一定的算法實現了分佈式 id 的唯一性和有序性,具體有興趣的可以看一下雪花算法的實現。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章