MySQL中UUID主鍵的優(yōu)化小結(jié)
UUID(Universally Unique IDentifier 通用唯一標(biāo)識(shí)符),是一種常用的唯一標(biāo)識(shí)符,在MySQL中,可以利用函數(shù)uuid()來生產(chǎn)UUID。因?yàn)閁UID可以唯一標(biāo)識(shí)記錄,因此有些場景可能會(huì)用來作為表的主鍵,但直接用UUID來作為主鍵可能存在性能缺陷,我們需要采取一些優(yōu)化手段。
一、UUID主鍵的缺陷
在MySQL中,innodb是按照表的聚簇索引(主鍵)來組織數(shù)據(jù)存儲(chǔ)的,也就是主鍵的順序決定了數(shù)據(jù)存儲(chǔ)的順序。這也是為什么我們通常推薦用整型,自增的數(shù)字來作為表的主鍵,當(dāng)新數(shù)據(jù)插入時(shí),主鍵一定是最大的,只要放在葉子層中最后的數(shù)據(jù)頁即可,對(duì)已有的數(shù)據(jù)不會(huì)有影響。
而如果用UUID來做主鍵,則會(huì)有2個(gè)缺陷:
- UUID的值是隨機(jī)的,因此新插入的數(shù)據(jù)有可能會(huì)插到已有數(shù)據(jù)的中間,這會(huì)導(dǎo)致整個(gè)索引樹的重新平衡和節(jié)點(diǎn)分裂,降低插入性能,數(shù)據(jù)量越大越嚴(yán)重。
- UUID是字符型,相對(duì)數(shù)字占用的存儲(chǔ)空間很大,這意味著主鍵很大,而主鍵又會(huì)附加到所有的二級(jí)索引中,因此所有的索引都很臃腫,消耗額外的磁盤和內(nèi)存資源,降低查詢性能。
UUID的生成方式有很多版本,這里舉2個(gè)最常用的:
- UUID V1: 通過時(shí)間戳和MAC地址來生成,可以生成順序的UUID。
- UUID V4: 通過隨機(jī)數(shù)來生成,無法生成順序的UUID。
MySQL自帶的函數(shù)uuid()是通過UUIDv1生成,因此上面第一個(gè)缺陷通常不存在,你需要注意的是某些應(yīng)用是否會(huì)自己生成非順序的UUID插入表中。
下面通過示例來看差別,我們創(chuàng)建兩張結(jié)構(gòu)一樣的表,一張用數(shù)字作為主鍵,一張用UUID作為主鍵:
create table digital_pk( id int auto_increment primary key, serial int); create table uuid_pk( id varchar(36) default(uuid()) primary key, serial int);
我們分別向2張表中插入5條數(shù)據(jù):
insert into digital_pk(serial) values(1); insert into digital_pk(serial) values(2); insert into digital_pk(serial) values(3); insert into digital_pk(serial) values(4); insert into digital_pk(serial) values(5);
insert into uuid_pk(serial) values(1); insert into uuid_pk(serial) values(2); insert into uuid_pk(serial) values(3); insert into uuid_pk(serial) values(4); insert into uuid_pk(serial) values(5);
我們通過explain來查看索引的信息:
explain select * from digital_pk where id=1\G
explain select * from uuid_pk where id='71b49d70-7f98-11ee-a9a1-0050569c9844'\G
可以看到uuid作為主鍵的長度是146,而數(shù)字做主鍵的長度為4,這意味著當(dāng)數(shù)據(jù)量非常大的時(shí)候,UUID的索引會(huì)非常臃腫,查詢性能會(huì)很低。
二、優(yōu)化方案
雖然通常不推薦使用UUID作為表的主鍵,但某些場景如果我們必須要用UUID作為主鍵,我們也可以通過一些方法來規(guī)避上述缺陷。
MySQL為了優(yōu)化UUID的存儲(chǔ),專門提供了兩個(gè)函數(shù):
- uuid_to_bin(uuid, swap_flag),將字符型UUID轉(zhuǎn)換為二進(jìn)制UUID,轉(zhuǎn)換后返回的數(shù)據(jù)類型是varbinary。
- bin_to_uuid(uuid, swap_flag),將二進(jìn)制UUID轉(zhuǎn)換為字符型UUID
在存儲(chǔ)的時(shí)候用uuid_to_bin(uuid, swap_flag)將UUID由字符型轉(zhuǎn)化為二進(jìn)制,可以大大縮小索引的長度,函數(shù)中的swap_flag有2個(gè)取值:
- 0 代表轉(zhuǎn)換后的數(shù)據(jù)依然是和UUID字符排序相同
- 1 代表轉(zhuǎn)換后將UUID中的time-low和time-high部分(第一和第三組)交換位置,轉(zhuǎn)換后數(shù)據(jù)可以按時(shí)間連續(xù)遞增,對(duì)InnoDB的聚簇索引還會(huì)有性能提升。注意這個(gè)僅對(duì)UUID V1版本基于時(shí)間戳生成的UUID才有效,如果是其他類型的UUID,不會(huì)得到性能提升。
下面我們利用這個(gè)函數(shù)新建一個(gè)表uuid_pk_v2:
create table uuid_pk_v2( id binary(16) default(uuid_to_bin(uuid(),1)) primary key, serial int);
- 這里id列的數(shù)據(jù)類型變成了binary(16),同時(shí)uuid在存儲(chǔ)時(shí)轉(zhuǎn)換為二進(jìn)制型存儲(chǔ)。
插入1條數(shù)據(jù)
insert into uuid_pk_v2(serial) values(1);
select id, serial from uuid_pk_v2; select bin_to_uuid(id,1), serial from uuid_pk_v2;
- 直接查詢是以16進(jìn)制顯示的數(shù)據(jù),這對(duì)我們沒有意義,我們需要用bin_to_uuid()函數(shù)將數(shù)據(jù)還原為字符串型UUID。
我們?cè)倏匆幌滤饕?/p>
explain select * from uuid_pk_v2 where id=uuid_to_bin('a292725f-7fa1-11ee-a9a1-0050569c9844',1)\G
- 索引的長度從164縮短為16,只有原來的十分之一,這代表索引在磁盤和內(nèi)存占用的空間也會(huì)縮小至十分之一,掃描速度會(huì)快的多。
- 因此,雖然在插入和查詢的時(shí)候多了一層函數(shù)的處理,但是這可以完美解決前面UUID的兩個(gè)缺陷,帶來的性能提升是完全值得的。
到此這篇關(guān)于MySQL中UUID主鍵的優(yōu)化小結(jié)的文章就介紹到這了,更多相關(guān)MySQL UUID主鍵優(yōu)化內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
騰訊面試:一條SQL語句執(zhí)行得很慢的原因有哪些?---不看后悔系列(推薦)
這篇文章主要介紹了SQL語句執(zhí)行慢的原因,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-04-04SQL實(shí)現(xiàn)LeetCode(184.系里最高薪水)
這篇文章主要介紹了SQL實(shí)現(xiàn)LeetCode(184.系里最高薪水),本篇文章通過簡要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-08-08mysql 獲取當(dāng)前日期函數(shù)及時(shí)間格式化參數(shù)詳解
這篇文章主要介紹了mysql 獲取當(dāng)前日期函數(shù)now()及時(shí)間格式化DATE_FROMAT函數(shù)以及參數(shù)詳細(xì)介紹,需要的朋友可以參考下2014-08-08win10下mysql 8.0.16 winx64安裝配置方法圖文教程
這篇文章主要為大家詳細(xì)介紹了win10下mysql 8.0.16 winx64安裝配置方法圖文教程,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-05-05安裝配置MySQLMTOP來監(jiān)控MySQL運(yùn)行性能的教程
這篇文章主要介紹了安裝配置MySQLMTOP來監(jiān)控MySQL運(yùn)行性能的教程,MySQLMTOP具有B/S方式的圖形化操作頁面,需要的朋友可以參考下2015-12-12