最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

MySql主鍵id不推薦使用UUID的原因分析

 更新時間:2023年03月06日 10:11:40   作者:你可以叫我老白  
MySQL的索引主要分為主鍵索引(PRIMARY KEY),唯一索引(UNIQUE) ,普通索引(INDEX)和全文索引(FULLTEXT) ,主鍵索引是一種特殊的唯一索引,不允許有空值,這篇文章主要介紹了MySql主鍵id不推薦使用UUID的原因分析,需要的朋友可以參考下

前言

昨天在某個技術群中,有個老哥發(fā)送了一個技術視頻:講的是一個畢業(yè)生面試被問,前后端的交互ID是使用自增的嗎?為什么不使用UUID?最后的解釋是說性能問題,這個引起了我的興趣,查了一下資料總結一下。

規(guī)范

在《阿里巴巴 Java 開發(fā)手冊》第五章 MySQL 規(guī)定第九條中,強制規(guī)定了單表的主鍵 id 必須為無符號的 bigint 類型,且是自增的。

MySQL開發(fā)規(guī)范中經(jīng)??梢钥吹剑?/p>

推薦使用int,bigint 無符號做自增鍵

禁止使用uuid做主鍵

關于主鍵的類型選擇上最常見的爭論是用整型還是字符型的問題,關于這個問題《高性能MySQL》一書中有明確論斷:

整數(shù)通常是標識列的最好選擇,因為它很快且可以使用AUTO_INCREAMENT,如果可能,應該避免使用字符串類型作為標識列,因為很消耗空間,且通常比數(shù)字類型慢。

如果是使用MyISAM,則就更不能用字符型,因為MyISAM默認會對字符型采用壓縮引擎,從而導致查詢變得非常慢。

原因

通常主鍵 id 的數(shù)據(jù)類型有兩種選擇:字符串或者整數(shù),主鍵通常要求是唯一的,如果使用字符串類型,我們可以選擇 UUID 或者具有業(yè)務含義的字符串來作為主鍵。

對于 UUID 而言,它由 32 個字符+4 個’-'組成,長度為 36,雖然 UUID 能保證唯一性,但是它有兩個致命的缺點:

1.不是遞增的。MySQL 中索引的數(shù)據(jù)結構是 B+Tree,這種數(shù)據(jù)結構的特點是索引樹上的節(jié)點的數(shù)據(jù)是有序的,而如果使用 UUID 作為主鍵,那么每次插入數(shù)據(jù)時,因為無法保證每次產(chǎn)生的 UUID 有序,所以就會出現(xiàn)新的 UUID 需要插入到索引樹的中間去,這樣可能會頻繁地導致頁分裂,使性能下降。

2.太占用內(nèi)存。每個 UUID 由 36 個字符組成,在字符串進行比較時,需要從前往后比較,字符串越長,性能越差。另外字符串越長,占用的內(nèi)存越大,由于頁的大小是固定的,這樣一個頁上能存放的關鍵字數(shù)量就會越少,這樣最終就會導致索引樹的高度越大,在索引搜索的時候,發(fā)生的磁盤 IO 次數(shù)越多,性能越差。

對于整數(shù)的數(shù)字類型,MySQL 中主要有 int 和 bigint 類型。其中 int 占用 4 個字節(jié),bigint 占用 8 個字節(jié),這和 Java 中的 int 和 long 對應。如果使用無符號的 int 類型作為主鍵,那么主鍵的最大值為 2^32-1,即 4294967295,這個值不到 43 億,似乎有點太小了。雖然一張表的數(shù)據(jù),我們不可能讓其達到 43 億條(太大會影響性能),但是對于頻繁進行插入、刪除的表來說,43 億這個值是可以達到的。而如果使用無符號的 bigint 類型的話,主鍵的最大值可以達到 2^64-1,這個數(shù)足夠大了,如果以每秒插入 100 萬條數(shù)據(jù)計算的,58 萬年以后才能達到最大值。所以 bigint 作為主鍵的數(shù)據(jù)類型,完全不用擔心超過最大值的問題。

而強制要求主鍵 id 是自增的,則是為了在數(shù)據(jù)插入的過程中,盡可能的避免索引樹上頁分裂的問題。

關于主鍵是聚簇索引,如果沒有主鍵,InnoDB會選擇一個唯一鍵來作為聚簇索引,如果沒有唯一鍵,會生成一個隱式的主鍵。

隱式主鍵:

InnoDB會自動幫你創(chuàng)建一個不可見的、長度為6字節(jié)的row_id,而且InnoDB維護了一個全局的dictsys.row_id,所有未定義主鍵的表都會共享該row_id,每次插入一條數(shù)據(jù)都把全局row_id當成主鍵id,然后全局row_id加1。

該全局row_id在代碼實現(xiàn)上使用的是bigint unsigned類型,但實際上只給row_id保留了6字節(jié),所以這種設計就會存在一個問題:如果全局row_id一直漲,直到2的48次冪-1時,這個時候再加1,row_id的低48位都會變?yōu)?,如果再插入新一行數(shù)據(jù)時,拿到的row_id就為0,這樣的話就存在主鍵沖突的可能,所以為了避免這種隱患,每個表都需要一個主鍵。

詳解-重點:

InnoDB引擎使用聚集索引,數(shù)據(jù)記錄本身被存于主索引(一顆B+Tree)的葉子節(jié)點上。這就要求同一個葉子節(jié)點內(nèi)(大小為一個內(nèi)存頁或磁盤頁)的各條數(shù)據(jù)記錄按主鍵順序存放,因此每當有一條新的記錄插入時,MySQL 會根據(jù)其主鍵將其插入適當?shù)墓?jié)點和位置,如果頁面達到裝載因子(InnoDB默認為15/16),則開辟一個新的頁(節(jié)點)

所以在使用innoDB表時要避免隨機的(不連續(xù)且值的分布范圍非常大)聚簇索引,特別是針對I/O密集型的應用。例如:從性能角度考慮,使用UUID的方案就會導致聚簇索引的插入變得完全隨機。

理論總結:

自增的主鍵的值是順序的,所以 Innodb 把每一條記錄都存儲在一條記錄的后面。

當達到頁面的最大填充因子時候 ( innodb默認的最大填充因子是頁大小的15/16,會留出1/16的空間留作以后的修改):

1)下一條記錄就會寫入新的頁中,一旦數(shù)據(jù)按照這種順序的方式加載,主鍵頁就會近乎于順序的記錄填滿,提升了頁面的最大填充率,不會有頁的浪費

2)新插入的行一定會在原有的最大數(shù)據(jù)行下一行,mysql定位和尋址很快,不會為計算新行的位置而做出額外的消耗

3)減少了頁分裂和碎片的產(chǎn)生

選擇 主鍵id:

tinyint、smallint、mediumint,這三個不常用就不說了。無符號是設置了 unsigned 屬性,表示不允許負值,這大致可以使正數(shù)的上限提高一倍。

以無符號int類型為例,42億雖然看起來是個很大的數(shù)字,但是對于一些插入刪除很頻繁的業(yè)務來說,并非無法觸達這個上限。特別是有的業(yè)務表設置的步長比較大,會導致id自增的速度更快。如果你的業(yè)務預期會產(chǎn)生很多數(shù)據(jù),那么建議你在創(chuàng)建表時,直接使用bigint。

因為MySQL的主鍵策略:id自增值達到上限以后,再申請下一個 id 時,仍然是最大值。

如果bigint真的還不夠使用的話,我們可以使用雪花算法生成的id做主鍵,由于其也是大致遞增的,對性能也不會產(chǎn)生影響,只需要由bigint改成更大范圍的decimal就行。

UUID:

一:使用場景

UUID是指在一臺機器上生成的數(shù)字,它保證對在同一時空中的所有機器都是唯一的。在UUID的算法中,可能會用到諸如網(wǎng)卡MAC地址,IP,主機名,進程ID等信息以保證其獨立性

二:有的開發(fā)就是喜歡使用UUID怎么辦?

所以MySQL8.0也是順應時代潮流,擔負時代的革命重任,MySQL8.0也對uuid的存儲做了進一步的提升。整體上看MySQL8.0現(xiàn)在的重點方向也是對開發(fā)的友好度支持上。

結論:

在MySQL8.0中還是推薦使用無符號的int, bigint做主鍵,如果要使用uuid可以建一個唯一索引

MySQL和Java兩者默認生成的uuid是version 1格式:datetime|mac地址,因為高低位順序亂了,造成順序亂掉,可以使用MySQL的函數(shù)uuid_to_bin(@uuid,1) , bin_to_uuid(@uuid,1)進行調(diào)整轉換,實現(xiàn)有序化

對于使用uuid_to_bin轉化后的uuid存儲,使用binary(16)或是varbinary(16)替代varchar(36),從而實現(xiàn)從36byte降到16byte。

這個技巧不是萬能的,如果你的數(shù)據(jù)庫CPU是瓶頸,使用轉化存儲,可能帶來CPU上更重的開銷,反之,如果你的IO是瓶頸,但CPU有較大的空閑,使用這個技巧就是一個不錯的優(yōu)化方案。如果不好把握,就用你可以用得到的最好硬件就可以了,一般情況下如果用上SSD后IO都沒啥問題,但也可以使用這個技術去降低表的物理大小。

實戰(zhàn):

環(huán)境準備

在MySQL 5.7中分別創(chuàng)建三張數(shù)據(jù)表:

test_varchar:以UUID作為主鍵。

test_long:以bigint作為主鍵。

test_int:以int作為主鍵。

三個表的字段,除了主鍵ID 分別采用varchar,bigint 和自動增長int不同外,其他三個字段都為 varchar 36位

另外,建表時使用InnoDB存儲引擎,并且向數(shù)據(jù)庫中插入100W條數(shù)據(jù),用以測試。

壓測信息

表類型:InnoDB

數(shù)據(jù)量:100W條

數(shù)據(jù)庫:

在這里插入圖片描述

主鍵采用uuid 32位

運行查詢語句1:
SELECT COUNT(id) FROM test_varchar;

運行查詢語句2:
SELECT * FROM test_varchar WHERE vname='71e88bab-2f0f-6811-89ff-4cc935c075d8';

運行查詢語句3:

SELECT * FROM test_varchar WHERE id='00004599b05211e196aa002655b28d7b';

三條查詢語句的耗時分別如下所示:

語句1消耗時間平均為:2.81秒;

語句2消耗時間平均為:3.11秒;

語句3消耗時間平均為:0秒;(多方測試,條件里只要有主鍵ID,查詢速度毫秒級都顯示000。測試的ID值,有前一百條的,也有后90多萬條的。查詢時間完全一樣,毫秒級都為000)

主鍵采用bigint

主鍵采用bigint,使用uuid_short()產(chǎn)生數(shù)據(jù),數(shù)據(jù)為有序列的純數(shù)字(22461015967875697)。(其相當于自動增長,只是固定的基數(shù)值較大而已。)

運行查詢語句1:

SELECT COUNT(id) FROM test_long;

運行查詢語句2:

SELECT * FROM test_long WHERE vname='63b10f80-0e20-28cc-3078-d7331ba410b6';

運行查詢語句3:

SELECT * FROM test_long WHERE id='22461015967875702';

三條查詢語句的耗時分別如下所示:

語句1消耗時間平均為:1.31秒;

語句2消耗時間平均為:1.51秒;

語句3消耗時間平均為:0秒;(多方測試,條件里只要有主鍵ID,查詢速度毫秒級都顯示000。測試的ID值,有前一百條的,也有后90多萬條的。查詢時間完全一樣,毫秒級都為000)

主鍵采用自增int

運行查詢語句1:

SELECT COUNT(id) FROM test_int;

運行查詢語句2:

SELECT * FROM test_int WHERE vname='908b57a5-cdef-32d1-0320-e14209b08894';

運行查詢語句3:

SELECT * FROM test_int WHERE id=900002;

其中,主鍵采用mysql自帶的自動增長,數(shù)據(jù)為純數(shù)字(1,2,3,4,5……)。

三條查詢語句的耗時分別如下所示:

查詢語句1消耗時間平均為:1.20秒;

查詢語句2消耗時間平均為:1.41秒;

查詢語句3消耗時間平均為:0秒;(多方測試,條件里只要有主鍵ID,查詢速度毫秒級都顯示000。測試的ID值,有前一百條的,也有后90多萬條的。查詢時間完全一樣,毫秒級都為000)

新增:

UUID做主鍵,其他字段相同,插入100萬條數(shù)據(jù),用了2.5個小時
自增主鍵,其他字段相同,插入相同的100萬條數(shù)據(jù),用了26分鐘

總結:由此可見,MySQL InnoDB 主鍵采用自動增長性能較高,但是在技術工作中,能否直接使用自增int類型的數(shù)字作為MySQL的主鍵,大家需要根據(jù)具體需求確定。

如果你設計的系統(tǒng),數(shù)據(jù)量還沒有超過100W,你用啥主鍵類型都無所謂。我測試電腦是臺式機,如果是專業(yè)的服務器,估計100W條,mysql MyISAM 的這些測試,根本都測不出來時間差吧。

到此這篇關于MySql主鍵id不推薦使用UUID的文章就介紹到這了,更多相關MySql主鍵id不推薦使用UUID內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • ubuntu下apt-get安裝和徹底卸載mysql詳解

    ubuntu下apt-get安裝和徹底卸載mysql詳解

    本文給大家分享ubuntu下apt-get安裝和徹底卸載mysql的方法,文中提到了安裝mysq命令查看mysql是否運行的命令寫法,具體內(nèi)容詳情大家通過本文學習吧
    2017-08-08
  • mysql數(shù)據(jù)庫開發(fā)規(guī)范【推薦】

    mysql數(shù)據(jù)庫開發(fā)規(guī)范【推薦】

    這篇文章主要介紹了mysql數(shù)據(jù)庫開發(fā)規(guī)范的相關內(nèi)容,還是十分不錯的,這里給大家分享下,需要的朋友可以參考。
    2017-10-10
  • MySQL?varchar(n)能存儲幾個漢字

    MySQL?varchar(n)能存儲幾個漢字

    這篇文章主要介紹了MySQL varchar(n)能存儲幾個漢字,MySQL中varchar(n)表示n個字符,無論漢字和英文,Mysql都能存入n個字符,僅是實際字節(jié)長度有所區(qū)別,本文給大家介紹的非常詳細,需要的朋友可以參考下
    2023-05-05
  • mysql批量新增和存儲的方法實例

    mysql批量新增和存儲的方法實例

    這篇文章主要給大家介紹了關于mysql批量新增和存儲的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2021-04-04
  • MySQL的Data_ADD函數(shù)與日期格式化函數(shù)說明

    MySQL的Data_ADD函數(shù)與日期格式化函數(shù)說明

    今天看到了MySQL的日期函數(shù),里面很多有用的,這里只把兩個參數(shù)不太好記的粘下來了。
    2010-06-06
  • Mysql服務器的啟動與停止(二)

    Mysql服務器的啟動與停止(二)

    Mysql服務器的啟動與停止(二)...
    2006-11-11
  • SQL?PRIMARY?KEY唯一標識表中記錄的關鍵約束語句

    SQL?PRIMARY?KEY唯一標識表中記錄的關鍵約束語句

    這篇文章主要為大家介紹了SQL?PRIMARY?KEY唯一標識表中記錄的關鍵約束語句詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-12-12
  • 詳解MySQL的主從復制、讀寫分離、備份恢復

    詳解MySQL的主從復制、讀寫分離、備份恢復

    本篇文章主要對MySQL的主從復制、讀寫分離、備份恢復進行詳細全面的講解,具有很好的參考價值,需要的朋友一起來看下吧
    2016-12-12
  • ORM模型框架操作mysql數(shù)據(jù)庫的方法

    ORM模型框架操作mysql數(shù)據(jù)庫的方法

    ORM 全稱是(Object Relational Mapping)表示對象關系映射; 通俗理解可以理解為編程語言的虛擬數(shù)據(jù)庫;這篇文章主要介紹了ORM模型框架操作mysql數(shù)據(jù)庫的方法,需要的朋友可以參考下
    2021-07-07
  • 使用SQL將多行記錄合并成一行實例代碼

    使用SQL將多行記錄合并成一行實例代碼

    今天同事問了一個需求,就是將多行數(shù)據(jù)合并成一行進行顯示,查詢了一些資料,這篇文章主要給大家介紹了關于使用SQL將多行記錄合并成一行的相關資料,需要的朋友可以參考下
    2022-09-09

最新評論

石泉县| 长宁县| 昌江| 新郑市| 德庆县| 什邡市| 隆回县| 扶风县| 红安县| 额敏县| 全州县| 甘谷县| 兴业县| 来宾市| 瑞丽市| 吐鲁番市| 佳木斯市| 丹江口市| 萝北县| 阳信县| 玛曲县| 兖州市| 高台县| 合水县| 长兴县| 讷河市| 镇原县| 黄平县| 洛宁县| 隆尧县| 永仁县| 隆德县| 江门市| 二连浩特市| 广东省| 尚志市| 苗栗市| 饶平县| 邓州市| 金昌市| 栾川县|