The UUID in MySQL8

問題

記得剛接手項目時,看了下項目里的庫表結(jié)構(gòu),發(fā)現(xiàn)表主鍵都是varchar(36),就問研發(fā),為啥搞個這么長的主鍵?研發(fā)說這個主鍵是通過java 程序產(chǎn)生的UUID,考慮到以后數(shù)據(jù)分片不會產(chǎn)生重復。我頓時無語,考慮的還是挺周到,沒有意識到這么長字段做主鍵的問題:

  • 首先這個主鍵很長,而主鍵會自動添加在每一二級索引的后面,這樣會導致數(shù)據(jù)冗余嚴重,特別是二級索引建多了的情況下,有時會導致索引的數(shù)據(jù)比表的數(shù)據(jù)還大!
  • 其次,這樣產(chǎn)生UUID是無序的,導致插入性能很差。因為當插入一個數(shù)據(jù)到B+tree時,系統(tǒng)將這個數(shù)據(jù)插入到一個合適的位置,這會導致多次IO,而如果數(shù)據(jù)本身是自增的,那么系統(tǒng)只須將它添加的B+Tree的末端即可,效率要高的多。

因此我還是建議使用整型+auto_increment, 雖然MySQLauto_increment有個眾所周知的、歷史悠久的bug(這個bug終于在MySQL8的到修復,MySQL8中auto_increment將會被寫入redo log 中啦),但大多數(shù)情況下還是可靠的,并且MySQL官方也建議使用auto_incremnet做主鍵。但它也有問題,就是無法適應數(shù)據(jù)分片的擴容(分庫分表),除非你之前規(guī)劃的非常好。

MySQL8中的解決方案

如今MySQL8 中對UUID提供了增強性支持,不僅使其長度大大縮小,而且解決了順序的問題?。ㄎ抑苑Q之為增強性支持,是因為他們提供了兩個內(nèi)置函數(shù)做了轉(zhuǎn)換,感覺這種方式有點兒low,這樣的函數(shù)我們也可以寫?。?/p>

大家都知道,UUID是由32位16進制字符串組成(不算分隔符'-')如:

62ab1547-710f-11e8-9a58-5254007205d6 

如果直接保存,則需要32個字符,utf8編碼下占用96個字節(jié),對于主鍵來說還是太長。幸運的是UUID中的每個字符都是16進制字符,兩個16進制字符占用一個字節(jié),這樣可以輕松將UUID轉(zhuǎn)換為binary(16),占用16個字節(jié),所需空間大大減少,而且二進制字符串檢索對比效率很高。

但還有一個至關重要的問題是UUID的組成中將timestamp 部分的低位時間段(如毫秒)放在了前面,高位時間段(如年月日)放在了后面,這會導致前面的字符變化很快,后面的變化很慢,從而使產(chǎn)生的UUID不能順序自增。這會導致索引插入效率大大降低。

為解決這一問題,mysql8提供了兩個函數(shù):UID_TO_BIN(arg1)/ BIN_TO_UUID(arg1,arg2)

  • UID_TO_BIN(arg1) 將UUID轉(zhuǎn)化為16位二進制字符串,如果參數(shù)arg1為true則將UUID中的timestamp部分中的time-low(第一段字符)和time-high(第三段)調(diào)換,這樣產(chǎn)生的UUID是順序遞增。
  • BIN_TO_UUID(arg1,arg2)將16位進制字符串轉(zhuǎn)化為可讀的UUID,arg1為16位二進制字符串,如果arg2省略或為false,即將二進制字符串原位轉(zhuǎn)換;如果arg2為true,則將原來調(diào)換的time-low和time-high再調(diào)換回去,返回原本的uuid.

測試

創(chuàng)建一張表如下:

mysql8[test]>create table t (id varbinary(16) primary key,create_time timestamp default current_timestamp());
Query OK, 0 rows affected (0.34 sec)

插入幾條數(shù)據(jù),注意使用了函數(shù)uuid_to_bin:

mysql8[test]>insert into t (id)values(uuid_to_bin(uuid(),true));
Query OK, 1 row affected (0.08 sec)

mysql8[test]>insert into t (id)values(uuid_to_bin(uuid(),true));
Query OK, 1 row affected (0.08 sec)

mysql8[test]>insert into t (id)values(uuid_to_bin(uuid(),true));
Query OK, 1 row affected (0.07 sec)

查看結(jié)果:

mysql8[test]>select bin_to_uuid(id) id1,bin_to_uuid(id,true) id2, create_time from t;
+--------------------------------------+--------------------------------------+---------------------+
| id1                                  | id2                                  | create_time         |
+--------------------------------------+--------------------------------------+---------------------+
| 11e87113-f079-024e-8405-5254004332fa | f079024e-7113-11e8-8405-5254004332fa | 2018-06-16 11:18:28 |
| 11e87113-f826-4134-8405-5254004332fa | f8264134-7113-11e8-8405-5254004332fa | 2018-06-16 11:18:41 |
| 11e87113-f88c-c8a6-8405-5254004332fa | f88cc8a6-7113-11e8-8405-5254004332fa | 2018-06-16 11:18:42 |
+--------------------------------------+--------------------------------------+---------------------+
3 rows in set (0.00 sec)

注意字段id1使用了函數(shù)bin_to_uuid(id), 而id2使用了bin_to_uuid(id,true),注意他們在結(jié)果集中的區(qū)別。

如果需要按主鍵查詢,還是需要使用對應的uuid函數(shù):

mysql8[test]>select * from t where id=uuid_to_bin('f079024e-7113-11e8-8405-5254004332fa',true);
+------------------+---------------------+
| id               | create_time         |
+------------------+---------------------+
| 簍??RT C2?? | 2018-06-16 11:18:28 |
+------------------+---------------------+
1 row in set (0.00 sec)

總結(jié)

MySQL8通過提供兩個內(nèi)置函數(shù)解決了傳統(tǒng)UUID作為主鍵的缺陷,也使UUID成為了設計主鍵的首選,特別是在數(shù)據(jù)分片的架構(gòu)中,其優(yōu)勢十分突出。我當時一看到這個,還很興奮,但UUID終究還不是一種數(shù)據(jù)類型,這多少給應用上增加了些麻煩。相信在MySQL的未來版本會出現(xiàn)一種數(shù)據(jù)類型叫UUID , 總不能一直弄兩個函數(shù)糊弄人吧??。ㄆ鋵嵞壳肮俜揭蔡岬搅藢崿F(xiàn)一種新的數(shù)據(jù)類型,但增加一種數(shù)據(jù)類型屬于重量級實現(xiàn),代碼變動太大,所以當前選擇了增加兩個函數(shù))

參考資料:

https://www.ietf.org/rfc/rfc4122.txt

https://dev.mysql.com/worklog/task/?id=8920
閱讀更多

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

  • MYSQL 基礎知識 1 MySQL數(shù)據(jù)庫概要 2 簡單MySQL環(huán)境 3 數(shù)據(jù)的存儲和獲取 4 MySQL基本操...
    Kingtester閱讀 8,075評論 5 115
  • 觀其大綱 page 01 基礎知識 1 MySQL數(shù)據(jù)庫概要 2 簡單MySQL環(huán)境 3 數(shù)據(jù)的存儲和獲取 4 M...
    周少言閱讀 3,256評論 0 33
  • 1.創(chuàng)建文件夾 !/bin/sh mkdir -m 777 "%%1" 2.創(chuàng)建文件 !/bin/sh touch...
    BigJeffWang閱讀 10,509評論 3 53
  • 第2章 基本語法 2.1 概述 基本句法和變量 語句 JavaScript程序的執(zhí)行單位為行(line),也就是一...
    悟名先生閱讀 4,619評論 0 13
  • 1.聽著歌看著炎熱夏季的窗外,聽著蟲兒叫我失眠,一個人聽著王力宏經(jīng)典歌曲,默默數(shù)著自己的傷口,但是誰會理解呢?...
    昂貴的青春閱讀 291評論 0 0

友情鏈接更多精彩內(nèi)容