欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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

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

前言

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

規(guī)范

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

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

推薦使用int,bigint 無符號(hào)做自增鍵

禁止使用uuid做主鍵

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

整數(shù)通常是標(biāo)識(shí)列的最好選擇,因?yàn)樗芸烨铱梢允褂肁UTO_INCREAMENT,如果可能,應(yīng)該避免使用字符串類型作為標(biāo)識(shí)列,因?yàn)楹芟目臻g,且通常比數(shù)字類型慢。

如果是使用MyISAM,則就更不能用字符型,因?yàn)镸yISAM默認(rèn)會(huì)對(duì)字符型采用壓縮引擎,從而導(dǎo)致查詢變得非常慢。

原因

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

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

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

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

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

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

關(guān)于主鍵是聚簇索引,如果沒有主鍵,InnoDB會(huì)選擇一個(gè)唯一鍵來作為聚簇索引,如果沒有唯一鍵,會(huì)生成一個(gè)隱式的主鍵。

隱式主鍵:

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

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

詳解-重點(diǎn):

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

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

理論總結(jié):

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

當(dāng)達(dá)到頁面的最大填充因子時(shí)候 ( innodb默認(rèn)的最大填充因子是頁大小的15/16,會(huì)留出1/16的空間留作以后的修改):

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

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

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

選擇 主鍵id:

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

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

因?yàn)镸ySQL的主鍵策略:id自增值達(dá)到上限以后,再申請(qǐng)下一個(gè) id 時(shí),仍然是最大值。

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

UUID:

一:使用場(chǎng)景

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

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

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

結(jié)論:

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

MySQL和Java兩者默認(rèn)生成的uuid是version 1格式:datetime|mac地址,因?yàn)楦叩臀豁樞騺y了,造成順序亂掉,可以使用MySQL的函數(shù)uuid_to_bin(@uuid,1) , bin_to_uuid(@uuid,1)進(jìn)行調(diào)整轉(zhuǎn)換,實(shí)現(xiàn)有序化

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

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

實(shí)戰(zhàn):

環(huán)境準(zhǔn)備

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

test_varchar:以UUID作為主鍵。

test_long:以bigint作為主鍵。

test_int:以int作為主鍵。

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

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

壓測(cè)信息

表類型:InnoDB

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

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

在這里插入圖片描述

主鍵采用uuid 32位

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

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

運(yùn)行查詢語句3:

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

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

語句1消耗時(shí)間平均為:2.81秒;

語句2消耗時(shí)間平均為:3.11秒;

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

主鍵采用bigint

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

運(yùn)行查詢語句1:

SELECT COUNT(id) FROM test_long;

運(yùn)行查詢語句2:

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

運(yùn)行查詢語句3:

SELECT * FROM test_long WHERE id='22461015967875702';

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

語句1消耗時(shí)間平均為:1.31秒;

語句2消耗時(shí)間平均為:1.51秒;

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

主鍵采用自增int

運(yùn)行查詢語句1:

SELECT COUNT(id) FROM test_int;

運(yùn)行查詢語句2:

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

運(yùn)行查詢語句3:

SELECT * FROM test_int WHERE id=900002;

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

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

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

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

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

新增:

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

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

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

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

相關(guān)文章

  • MYSQL輸入密碼后閃退現(xiàn)象的解決方法

    MYSQL輸入密碼后閃退現(xiàn)象的解決方法

    最近在啟動(dòng)MySQL服務(wù)端并輸入密后,出現(xiàn)閃退現(xiàn)象,實(shí)際上這種問題很常見,下面這篇文章主要給大家介紹了關(guān)于MYSQL輸入密碼后閃退現(xiàn)象的解決方法,文中介紹的非常詳細(xì),需要的朋友可以參考下
    2023-05-05
  • mysql 8.0.19 安裝配置方法圖文教程

    mysql 8.0.19 安裝配置方法圖文教程

    這篇文章主要為大家詳細(xì)介紹了mysql 8.0.19 安裝配置方法圖文教程,文中安裝步驟介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-02-02
  • mysql odbc字符集設(shè)置(中文顯示亂碼)

    mysql odbc字符集設(shè)置(中文顯示亂碼)

    mysql odbc字符集設(shè)置(中文顯示亂碼),碰到這個(gè)問題的朋友可以參考下。
    2011-08-08
  • MySQL-group-replication 配置步驟(推薦)

    MySQL-group-replication 配置步驟(推薦)

    下面小編就為大家?guī)硪黄狹ySQL-group-replication 配置步驟(推薦)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-03-03
  • MySQL 5.6.51 解壓版(zip版)安裝配置圖文方法

    MySQL 5.6.51 解壓版(zip版)安裝配置圖文方法

    這兩天剛試用了一下MySQL5.6.51,感覺還不錯(cuò),有兄弟戲稱是一個(gè)高富帥版本?,F(xiàn)將MySQL5.6.51 zip解壓版本的安裝配置過程記錄如下,希望能給需要安裝該版本的朋友一點(diǎn)參考作用
    2015-08-08
  • Dbeaver連接MySQL數(shù)據(jù)庫及錯(cuò)誤Connection?refusedconnect處理方法

    Dbeaver連接MySQL數(shù)據(jù)庫及錯(cuò)誤Connection?refusedconnect處理方法

    這篇文章主要介紹了dbeaver連接MySQL數(shù)據(jù)庫及錯(cuò)誤Connection?refusedconnect處理方法,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-08-08
  • Mysql binlog日志文件過大的解決

    Mysql binlog日志文件過大的解決

    本文主要介紹了Mysql binlog日志文件過大的解決,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-09-09
  • MySQL實(shí)現(xiàn)批量插入以優(yōu)化性能的教程

    MySQL實(shí)現(xiàn)批量插入以優(yōu)化性能的教程

    這篇文章主要介紹了MySQL實(shí)現(xiàn)批量插入以優(yōu)化性能的教程,文中給出了運(yùn)行時(shí)間來表示性能優(yōu)化后的對(duì)比,需要的朋友可以參考下
    2015-04-04
  • MySQL之DATE_ADD()和DATE_SUB()函數(shù)的使用方式

    MySQL之DATE_ADD()和DATE_SUB()函數(shù)的使用方式

    這篇文章主要介紹了MySQL之DATE_ADD()和DATE_SUB()函數(shù)的使用方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-04-04
  • mysql 安全管理詳情

    mysql 安全管理詳情

    這篇文章主要介紹了mysql 安全管理,MySQL服務(wù)器的安全基礎(chǔ)是用戶應(yīng)該對(duì)他們需要的數(shù)據(jù)具有適當(dāng)?shù)脑L問權(quán),既不能多也不能少,換句話說,用戶不能對(duì)過多的數(shù)據(jù)具有過多的訪問權(quán),下面?zhèn)z看看文章詳細(xì)內(nèi)容吧
    2021-10-10

最新評(píng)論