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