【原創】雜談自增主鍵用完了怎麼辦

引言

在面試中,你們應該經歷過以下場景html

面試官:"用過mysql吧,大家是用自增主鍵仍是UUID?"
你:"用的是自增主鍵"
面試官:"爲何是自增主鍵?"
你:"由於採用自增主鍵,數據在物理結構上是順序存儲,性能最好,blabla..."
面試官:"那自增主鍵達到最大值了,用完了怎麼辦?"
你:"what,沒複習啊!!"
(而後,你就能夠回去等通知了!)
mysql

這個問題是一個粉絲給我提的,我以爲挺有意(KENG)思(B)!
因而,今天咱們就來談一談,這個自增主鍵用完了該怎麼辦!面試

正文

簡單版

咱們先明白一點,在mysql中,Int整型的範圍以下sql

類型 最小值 最大值 存儲大小
Int(有符號) -2147483648 2147483648 4 bytes
Int(無符號) 0 4294967295 4 bytes

咱們以無符號整型爲例,存儲範圍爲0~4294967295,約43億!咱們先說一下,一旦自增id達到最大值,此時數據繼續插入是會報一個主鍵衝突異常以下所示數據庫

//Duplicate entry '4294967295' for key 'PRIMARY'

那解決方法也是很簡單的,將Int類型改成BigInt類型,BigInt的範圍以下數據結構

類型 最小值 最大值 存儲大小
BigInt(有符號) -9223372036854775808 9223372036854775808 8 bytes
BigInt(無符號) 0 18446744073709551615 8 bytes

就算你每秒10000條數據,跑100年,單表的數據也才
10000*24*3600*365*100=31536000000000
這數字距離BigInt的上限還差的遠,所以你將自增ID設爲BigInt類型,你是不用考慮自增ID達到最大值這個問題!
然而,若是你在面試中的回答若是是架構

你:"簡單啊,把自增主鍵的類型改成BigInt類型就行了!"併發

接下來,面試官能夠問你一個更坑的問題!工具

面試官:"你在線上怎麼修改列的數據類型的?"
你:"what!我仍是回等通知吧!"
性能

怎麼改

目前業內在線修改表結構的方案,據我瞭解,通常有以下三種
方式一:使用mysql5.6+提供的在線修改功能
所謂的mysql本身提供的功能也就是mysql本身原生的語句,例如咱們要修改原字段名稱及類型。

mysql> ALTER TABLE table_name CHANGE old_field_name new_field_name field_type;

那麼,在mysql5.5這個版本以前,這是經過臨時表拷貝的方式實現的。執行ALTER語句後,會新建一個帶有新結構的臨時表,將原表數據所有拷貝到臨 時表,而後Rename,完成建立操做。這個方式過程當中,原表是可讀的,不可寫。可是會消耗一倍的存儲空間。
在5.6+開始,mysql支持在線修改數據庫表,在修改表的過程當中,對絕大部分操做*,原表可讀,也能夠寫。
那麼,對於修改列的數據類型這種操做,原表還能寫麼?來來來,煙哥特地去官網找了mysql8.0版本的一張圖

如圖所示,對於修改數據類型這種操做,是不支持併發的DML操做!也就是說,若是你直接使用ALTER這樣的語句在線修改表數據結構,會致使這張表沒法進行更新類操做(DELETEUPDATEDELETE)。
所以,直接ALTER是不行滴!

那咱們只能用方式二或者方式三
方式二:藉助第三方工具
業內有一些第三方工具能夠支持在線修改表結構,使用這些第三發工具,可以讓你在執行ALTER操做的時候,表不會阻塞!比較出名的有兩個

  • 一、pt-online-schema-change,簡稱pt-osc
  • 二、GitHub正式宣佈以開源的方式發佈的工具,名爲gh-ost

pt-osc爲例,它的原理以下

  • 一、建立一個新的表,表結構爲修改後的數據表,用於從源數據表向新表中導入數據。
  • 二、建立觸發器,用於記錄從拷貝數據開始以後,對源數據表繼續進行數據修改的操做記錄下來,用於數據拷貝結束後,執行這些操做,保證數據不會丟失。
  • 三、拷貝數據,從源數據表中拷貝數據到新表中。
  • 四、rename源數據表爲old表,把新表rename爲源表名,並將old表刪除。
  • 五、刪除觸發器。

然而這兩個有意(KENG)思(B)的工具,竟然。。。竟然。。。唉!若是你的表裏有觸發器和外鍵,這兩個工具是不行滴!
若是真碰上了數據庫裏有觸發器和外鍵,只能硬槓了,請看方式三
方式三:改從庫表結構,而後主從切換
此法極其麻煩,須要專業水平的選手進行操做。由於咱們的mysql架構通常是讀寫分離架構,從機是用來讀的。咱們直接在從庫上進行表結構修改,不會阻塞從庫的讀操做。改完以後,進行主從切換便可。惟一須要注意的是,主從切換過程當中可能會有數據丟失的狀況!

高深版

其實答完上面的問題後,這篇文章差很少完了。可是,還記得我在開頭說的麼。這是一個頗有意(KENG)思(B)的問題,爲何呢?
假設啊,你的表裏的自增字段爲有符號的Int類型的,也就是說,你的字段範圍爲-2147483648到2147483648。
一切又那麼恰好,你的自增ID是從0開始的,也就是說,如今你的能夠用的範圍爲0~2147483648。
咱們明確一點,表中真實的數據ID,確定會出現一些意外,ID不必定是連續的。例如,有以下情形的出現

CREATE TABLE `t` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  PRIMARY KEY (`id`),
) ENGINE=InnoDB;

執行下列SQL

insert into t values(null);
// 插入的行是 (1)
begin;
insert into t values(null);
rolllack;
insert into t values(null);
// 插入的行是 (3)

所以,表中的真實id必然會出現斷續的狀況。
好,那這會你的自增主鍵id的數據範圍爲0~2147483648,也就是單表21億條數據!考慮id會出現斷續,真實數據頂多18億條吧。
老哥,都單表18億條了,還不分庫分表?你一旦分庫分表了,就不能依賴於每一個表的自增ID來全局惟一標識這些數據了。此時,咱們就須要提供一 個全局惟一的ID號生成策略來支持分庫分表的環境。所以,你須要關注的文章是《分庫分表後如何上線部署》

所以在實際中,你根本等不到自增主鍵用完到情形!
因此,專業版回答以下

面試官:"那自增主鍵達到最大值了,用完了怎麼辦?" 你:"這問題沒遇到過,由於自增主鍵通常用int類型,通常達不到最大值,咱們就分庫分表了,因此未曾碰見過!"

相關文章
相關標籤/搜索