在MySQL中用UUID當主鍵,被組長給噴了!
我們在使用MySQL的時候,主鍵的選擇上一般有兩種,那就是UUID和自增主鍵ID,使用這兩個做主鍵各自都有哪些優缺點呢?為什么建議優先使用自增主鍵ID呢?
UUID唯一嗎
UUID(Universally Unique Identifier)全局唯一標識符,是指在一臺機器上生成的數字,它的目標是保證對在同一時空中的所有機器都是唯一的。
UUID 的生成是基于一定算法,通常使用的是隨機數生成器或者基于時間戳的方式,生成的 UUID 由 32 位 16 進制數表示,共有 128 位(標準的UUID格式為:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx (8-4-4-4-12),共32個字符)
由于 UUID 是由 MAC 地址、時間戳、隨機數等信息生成的,因此 UUID 具有極高的唯一性,可以說是幾乎不可能重復,但是在實際實現過程中,UUID有多種實現版本,他們的唯一性指標也不盡相同。
UUID在具體實現上,有多個版本,有基于時間的UUID V1,基于隨機數的 UUID V4等。
Java中的java.util.UUID生成的UUID是V3和V4兩種:
Version 4 這種是最簡單的(也是我們最常用的),只是基于隨機數生成的,但是也是最不靠譜的。適合數據量不是特別大的場景下。
Version 3是基于名稱空間的,所以在一定范圍內是唯一的,而且如果有需要生成重復UUID的場景的話,這兩種是可以實現的。
UUID的好處
很多人選擇UUID作為主鍵,其實也是有一定道理的,那就是UUID有幾何好處:
- 全局唯一:使用不同的算法生成,雖然不能100%保證唯一,但是在非并發場景下幾乎可以保證在全球范圍內唯一,避免了多臺機器之間主鍵沖突的問題。
- 不可預測性:隨機生成的 UUID 很難被猜測出來,對于需要保密性的應用場景較為適用。
- 分布式:由于可以在不同的機器上生成 UUID,因此可以用于分布式系統中,如分庫分表場景。
UUID的缺點
但是,如果只是因為這幾個好處就選擇UUID當做主鍵ID的話,那么也不是很好的方案,因為他的缺點也比較明顯,如:
存儲空間比較大:UUID 通常以字符串形式存儲,占用的存儲空間比較大。
不適合范圍查詢:因為不是自增的,所以在做范圍查詢的時候是不支持的。
不方便展示:主鍵ID有的時候會需要在系統間、或者前臺頁面展示,如果是UUID的話,就因為比較長、并且沒有任何業務含義,所以不方便展示。
查詢效率低:
在UUID列上創建索引,因為他很長,所以索引的大小會變得非常大。大的索引會占用更多的磁盤空間,導致緩存命中率下降,進而增加了磁盤I/O的需求。此外,大的索引還會導致查詢時的內存開銷增加。
當使用UUID進行排序時,新的UUID值通常會插入到葉子節點的中間位置。這可能導致B+樹的頁分裂和平衡操作頻繁進行,從而增加了寫入的開銷。每次分裂或平衡都涉及到數據的重新排序和移動,這會影響查詢的性能。
自增ID
在 MySQL 中,可以通過設置 AUTO_INCREMENT 屬性實現ID的自增長,通常可以用來作為主鍵ID。
使用自增ID做主鍵的好處是:
- 存儲空間:ID是數字,所以占用的位數要比UUID小多了,所以在存儲空間上也節省很多。
- 查詢效率:ID 是遞增的,因此在使用 B+Tree 索引時,查詢效率較高。
- 方便展示:因為ID比較短,方便展示。
- 分頁方便:因為ID是連續自增的,所以在分頁的時候,可以通過ID解決深度分頁的問題。
但是,使用自增主鍵做主鍵ID也存在一定的問題:
- 分庫分表:當我們做分庫分表的時候,就沒辦法依賴一張表的自增主鍵來做主鍵ID了,這樣就會發生重復導致沖突的問題
- 可預測:因為ID是順序自增的,所以是可以預測的,這就給系統帶來了一定的安全風險。
- 可能用盡:自增id的話可能是int、bigint等,但是他們都是有范圍的,有可能會用盡
總結
所以,在實際選型過程中,大家需要結合自己的實際業務做選擇。
簡單的業務場景,數據量不大,增刪改查也不頻繁,可以選擇用UUID。
內部系統,數據量增刪改查頻繁,有頻繁的分頁查詢和展示等需求,優先選擇自增主鍵ID。
對外系統,數據量不大,也可以選用自增主鍵ID。
對外系統,數據量大,分庫分表,則考慮使用雪花算法生成全局唯一ID。