在面試中,大家應(yīng)該經(jīng)歷過(guò)如下場(chǎng)景
面試官:"用過(guò)mysql吧,你們是用自增主鍵還是UUID?"
你:"用的是自增主鍵" 面試官:"為什么是自增主鍵?"
你:"因?yàn)椴捎米栽鲋麈I,數(shù)據(jù)在物理結(jié)構(gòu)上是順序存儲(chǔ),性能最好,blabla..."
面試官:"那自增主鍵達(dá)到最大值了,用完了怎么辦?"
你:"what,沒(méi)復(fù)習(xí)啊?。? (然后,你就可以回去等通知了!)
今天我們就來(lái)談一談,這個(gè)自增主鍵用完了該怎么辦!
一、關(guān)于自增ID
https://mp.weixin.qq.com/s/hkYcXap1FmtuEFWsxwEDDg,這篇文章介紹了好幾種自增id,每種自增 id 有各自的應(yīng)用場(chǎng)景,在達(dá)到上限后的表現(xiàn)也不同:
1、?表的自增 id 達(dá)到上限后,再申請(qǐng)時(shí)它的值就不會(huì)改變,進(jìn)而導(dǎo)致繼續(xù)插入數(shù)據(jù)時(shí)報(bào)主鍵沖突的錯(cuò)誤
2、?row_id 達(dá)到上限后,則會(huì)歸 0 再重新遞增,如果出現(xiàn)相同的 row_id,后寫(xiě)的數(shù)據(jù)會(huì)覆蓋之前的數(shù)據(jù)
3、?Xid 只需要不在同一個(gè) binlog 文件中出現(xiàn)重復(fù)值即可。雖然理論上會(huì)出現(xiàn)重復(fù)值,但是概率極小,可以忽略不計(jì)
4、?InnoDB 的 max_trx_id 遞增值每次 MySQL 重啟都會(huì)被保存起來(lái),所以我們文章中提到的臟讀的例子就是一個(gè)必現(xiàn)的 bug,好在留給我們的時(shí)間還很充裕
5、?thread_id 是我們使用中最常見(jiàn)的,而且也是處理得最好的一個(gè)自增 id 邏輯了
6、?redis外部自增,毫秒級(jí)別,理論上會(huì)出現(xiàn)重復(fù)值,但是概率極小,可以忽略不計(jì)
7、?其實(shí),每種自增id都有各自的適用場(chǎng)景,大家在平時(shí)使用中可以根據(jù)具體場(chǎng)景再選擇。但是要未雨綢繆,因?yàn)橄到y(tǒng)的運(yùn)行時(shí)間和數(shù)據(jù)的存儲(chǔ),這些都是要考慮在內(nèi)的,綜合考慮,選擇一個(gè)在系統(tǒng)運(yùn)行期間一定不會(huì)出現(xiàn)重復(fù)即刻。你學(xué)會(huì)了嗎?
二、自增 ID 用完怎么辦
1、簡(jiǎn)單回答版? ——? int 改為 bigint
我們先明白一點(diǎn),在mysql中,Int整型的范圍如下:
我們以無(wú)符號(hào)整型為例,存儲(chǔ)范圍為0~4294967295,約43億!我們先說(shuō)一下,一旦自增id達(dá)到最大值,此時(shí)數(shù)據(jù)繼續(xù)插入是會(huì)報(bào)一個(gè)主鍵沖突異常如下所示
//Duplicate entry '4294967295' for key 'PRIMARY'
那解決方法也是很簡(jiǎn)單的,將Int類(lèi)型改為BigInt類(lèi)型,BigInt的范圍如下
就算你每秒10000條數(shù)據(jù),跑100年,單表的數(shù)據(jù)也才 10000*24*3600*365*100=31536000000000,
這數(shù)字距離BigInt的上限還差的遠(yuǎn),因此你將自增ID設(shè)為BigInt類(lèi)型,你是不用考慮自增ID達(dá)到最大值這個(gè)問(wèn)題! 然而,如果你在面試中的回答如果是
你:"簡(jiǎn)單啊,把自增主鍵的類(lèi)型改為BigInt類(lèi)型就好了!"
接下來(lái),面試官可以問(wèn)你一個(gè)更坑的問(wèn)題!
面試官:"你在線上怎么修改列的數(shù)據(jù)類(lèi)型的?" 你:"what!我還是回等通知吧!"
2、如何在生產(chǎn)環(huán)境修改列的數(shù)據(jù)類(lèi)型
目前業(yè)內(nèi)在線修改表結(jié)構(gòu)的方案,據(jù)我了解,一般有如下三種
(1)方式一:使用mysql5.6+提供的在線修改功能
所謂的mysql自己提供的功能也就是mysql自己原生的語(yǔ)句,例如我們要修改原字段名稱(chēng)及類(lèi)型。
mysql> ALTER TABLE table_name CHANGE old_field_name new_field_name field_type;
那么,在mysql5.5這個(gè)版本之前,這是通過(guò)臨時(shí)表拷貝的方式實(shí)現(xiàn)的。執(zhí)行ALTER
語(yǔ)句后,會(huì)新建一個(gè)帶有新結(jié)構(gòu)的臨時(shí)表,將原表數(shù)據(jù)全部拷貝到臨 時(shí)表,然后Rename,完成創(chuàng)建操作。這個(gè)方式過(guò)程中,原表是可讀的,不可寫(xiě)。但是會(huì)消耗一倍的存儲(chǔ)空間。 在5.6+開(kāi)始,mysql支持在線修改數(shù)據(jù)庫(kù)表,在修改表的過(guò)程中,對(duì)絕大部分操作,原表可讀,也可以寫(xiě)。
那么,對(duì)于修改列的數(shù)據(jù)類(lèi)型這種操作,原表還能寫(xiě)么?官網(wǎng)mysql8.0版本的一張圖
我們可以看到:如圖所示,change the column data type 對(duì)于修改數(shù)據(jù)類(lèi)型這種操作,是不支持并發(fā)的DML操作!也就是說(shuō),如果你直接使用ALTER
這樣的語(yǔ)句在線修改表數(shù)據(jù)結(jié)構(gòu),會(huì)導(dǎo)致這張表無(wú)法進(jìn)行更新類(lèi)操作(DELETE
、UPDATE
、DELETE
)。 因此,直接ALTER
是不行滴!
那我們只能用方式二或者方式三。
(2)方式二:借助第三方工具
業(yè)內(nèi)有一些第三方工具可以支持在線修改表結(jié)構(gòu),使用這些第三發(fā)工具,能夠讓你在執(zhí)行ALTER
操作的時(shí)候,表不會(huì)阻塞!
比較出名的有兩個(gè):1、pt-online-schema-change
,簡(jiǎn)稱(chēng) pt-osc;
2、GitHub正式宣布以開(kāi)源的方式發(fā)布的工具,名為 gh-ost
以pt-osc
為例,它的原理如下:
- 1、創(chuàng)建一個(gè)新的表,表結(jié)構(gòu)為修改后的數(shù)據(jù)表,用于從源數(shù)據(jù)表向新表中導(dǎo)入數(shù)據(jù)。
- 2、創(chuàng)建觸發(fā)器,用于記錄從拷貝數(shù)據(jù)開(kāi)始之后,對(duì)源數(shù)據(jù)表繼續(xù)進(jìn)行數(shù)據(jù)修改的操作記錄下來(lái),用于數(shù)據(jù)拷貝結(jié)束后,執(zhí)行這些操作,保證數(shù)據(jù)不會(huì)丟失。
- 3、拷貝數(shù)據(jù),從源數(shù)據(jù)表中拷貝數(shù)據(jù)到新表中。
- 4、rename源數(shù)據(jù)表為old表,把新表rename為源表名,并將old表刪除。
- 5、刪除觸發(fā)器。
然而這兩個(gè)有意(KENG)思(B)
的工具,居然也有坑!如果你的表里有觸發(fā)器和外鍵,這兩個(gè)工具是不行滴! 如果真碰上了數(shù)據(jù)庫(kù)里有觸發(fā)器和外鍵,只能硬杠了,請(qǐng)看方式三。
(3)方式三:改從庫(kù)表結(jié)構(gòu),然后主從切換
此法極其麻煩,需要專(zhuān)業(yè)水平的選手進(jìn)行操作。因?yàn)槲覀兊膍ysql架構(gòu)一般是讀寫(xiě)分離架構(gòu),從機(jī)是用來(lái)讀的。我們直接在從庫(kù)上進(jìn)行表結(jié)構(gòu)修改,不會(huì)阻塞從庫(kù)的讀操作。改完之后,進(jìn)行主從切換即可。唯一需要注意的是,主從切換過(guò)程中可能會(huì)有數(shù)據(jù)丟失的情況!
3、高深版
其實(shí)答完上面的問(wèn)題后,這篇文章差不多完了。但是,還記得我在開(kāi)頭說(shuō)的么。這是一個(gè)很有意(KENG)思(B)
的問(wèn)題,為什么呢?
假設(shè)啊,你的表里的自增字段為有符號(hào)的Int類(lèi)型的,也就是說(shuō),你的字段范圍為-2147483648到2147483648。 一切又那么剛好,你的自增ID是從0開(kāi)始的,也就是說(shuō),現(xiàn)在你的可以用的范圍為0~2147483648。 我們明確一點(diǎn),表中真實(shí)的數(shù)據(jù)ID,肯定會(huì)出現(xiàn)一些意外,ID不一定是連續(xù)的。
因此,表中的真實(shí)id必然會(huì)出現(xiàn)斷續(xù)的情況。 好,那這會(huì)你的自增主鍵id的數(shù)據(jù)范圍為0~2147483648,也就是單表21億條數(shù)據(jù)!考慮id會(huì)出現(xiàn)斷續(xù),真實(shí)數(shù)據(jù)頂多18億條吧。 老哥,都單表18億條了,還不分庫(kù)分表?
你一旦分庫(kù)分表了,就不能依賴(lài)于每個(gè)表的自增ID來(lái)全局唯一標(biāo)識(shí)這些數(shù)據(jù)了。此時(shí),我們就需要提供一 個(gè)全局唯一的ID號(hào)生成策略來(lái)支持分庫(kù)分表的環(huán)境。
所以,你需要關(guān)注的文章是《分庫(kù)分表后如何上線部署》
因此在實(shí)際中,你根本等不到自增主鍵用完到情形! 所以,專(zhuān)業(yè)版回答如下
面試官:"那自增主鍵達(dá)到最大值了,用完了怎么辦?"
你:"這問(wèn)題沒(méi)遇到過(guò),因?yàn)樽栽鲋麈I一般用int類(lèi)型,一般達(dá)不到最大值,我們就分庫(kù)分表了,所以不曾遇見(jiàn)過(guò)!"
原文鏈接:https://zhuanlan.zhihu.com/p/61690701
本文摘自 :https://www.cnblogs.com/