MySQL中的自增主鍵用完了怎麼辦?

2020-10-13 阿毛雜記

前言

在面試中,大家是否經歷過如下場景:

面試官:"用過mysql吧,你們是用自增主鍵還是UUID?"

你:"用的是自增主鍵"

面試官:"為什麼是自增主鍵?"

你:"因為採用自增主鍵,數據在物理結構上是順序存儲,性能最好,blabla…"

面試官:"那自增主鍵達到最大值了,用完了怎麼辦?"

你:"what,沒複習啊!!" (然後,你就可以回去等通知了!)


正文

我們先明白一點,在mysql中,Int整型的範圍如下

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

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

那解決方法也是很簡單的,將Int類型改為BigInt類型,BigInt的範圍如下

就算你每秒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這樣的語句在線修改表數據結構,會導致這張表無法進行更新類操作(DELETE、UPDATE、DELETE)。因此,直接ALTER是不行滴!

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

  • pt-online-schema-change,簡稱pt-osc
  • GitHub正式宣布以開源的方式發布的工具,名為gh-ost

以pt-osc為例,它的原理如下

  • 1、創建一個新的表,表結構為修改後的數據表,用於從源數據表向新表中導入數據。
  • 2、創建觸發器,用於記錄從拷貝數據開始之後,對源數據表繼續進行數據修改的操作記錄下來,用於數據拷貝結束後,執行這些操作,保證數據不會丟失。
  • 3、拷貝數據,從源數據表中拷貝數據到新表中。
  • 4、rename源數據表為old表,把新表rename為源表名,並將old表刪除。
  • 5、刪除觸發器。

然而這兩個有意(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`),) EN

執行下列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類型,一般達不到最大值,我們就分庫分表了,所以不曾遇見過!"


相關焦點

  • MySQL表自增id用完了該怎麼辦?
    我們知道MySQL表可以定義一個自增長的id,如果我們的表沒有指定主鍵欄位,那MySQL會給我們的表創建一個不可見的,長度為6個自己的row_id,然後不停地往上加步長,雖然生活中自然數是沒有上限的,但是在計算機裡,我們只要定義了表示這個數的字節長度,那麼它就有上限,比如在Java中,int類型的上限值為2^31-1,即2147483647。
  • 面試官問:MySQL 的自增 ID 用完了,怎麼辦?
    首先,創建一個最簡單的表,只包含一個自增 id,並插入一條數據。,我們可以算下最大當前聲明的自增 ID 最大是多少,由於這裡定義的是 intunsigned,所以最大可以達到 2 的 32 冪次方 - 1 = 4294967295這裡有個小技巧,可以在創建表的時候,直接聲明 AUTO_INCREMENT 的初始值create table
  • 面試官問:MySQL 的自增 ID 用完了,怎麼辦?
    本文轉載自【微信公眾號:java進階架構師,ID:java_jiagoushi】經微信公眾號授權轉載,如需轉載與原文作者聯繫首先,創建一個最簡單的表,只包含一個自增 id,並插入一條數據。,我們可以算下最大當前聲明的自增 ID 最大是多少,由於這裡定義的是 intunsigned,所以最大可以達到 2 的 32 冪次方 - 1 = 4294967295這裡有個小技巧,可以在創建表的時候,直接聲明 AUTO_INCREMENT 的初始值create table t1(id int unsigned auto\_increment
  • MySQL中的各種自增ID
    表自增主鍵的自增值如果一張表的自增ID用完之後,我們再次向這個表中插入數據會怎麼樣呢?我們使用tinyint類型的自增主鍵舉例舉例來實驗一下。)整個過程截圖如下,從中我可以可以看出,當自增主鍵的值,達到最大值之後,我們再次向表中插入數據的時候。
  • Mysql 8新特性之(5):自增主鍵的bug已修復
    問題歷史背景是自增主鍵沒有持久化是個比較早的bug.MySQL5.7及以前版本MySQL伺服器重啟,會重新掃描表的主鍵最大值,如果之前已經刪除過id=100的數據,但是表中當前記錄的最大值如果是99,那麼經過掃描,下一條記錄的id是100,而不是101。
  • 面試官:資料庫自增ID用完了會怎麼樣?
    這些都是題外話,只是告訴你數據量大了是有可能達到上限的而已,回到Mysql自增ID上限的問題,可以分為兩個方面來說。1.有主鍵如果設置了主鍵,並且一般會把主鍵設置成自增。我們知道,Mysql裡int類型是4個字節,如果有符號位的話就是[-2^31,2^31-1],無符號位的話最大值就是2^32-1,也就是4294967295。
  • 程式設計師經典面試題,Mysql自增主鍵為什麼不連續
    在我們日常使用Mysql中,如果不是特殊的業務需要,一般我們都會使用自增主鍵,自增主鍵的好處可以在插入的時候儘量地減少頁分割,增加Mysql的寫入效率。我們有時候就會發現,自增主鍵並不是連續遞增的,為什麼有時候會出現自增主鍵的空洞呢?
  • 為啥不能用uuid做MySQL的主鍵?
    前言在mysql中設計表的時候,mysql官方推薦不要使用uuid或者不連續不重複的雪花id(long形且唯一,單機遞增),而是推薦連續自增的主鍵id,官方的推薦是auto_increment,那麼為什麼不建議採用uuid,使用uuid究竟有什麼壞處?
  • 關於主鍵,除了自增,你還可以這樣
    的IDENTITY,Oracle則是通過SEQUENCE來實現主鍵自增。使用自增主鍵,比較簡單,佔用空間較小;主鍵按順序增長存放,不會產生頁分裂;同時也有一些不足,如多個系統之間集成數據時,容易有主鍵衝突;單表自增對於資料庫單表壓力較大,不適用於高並發及分布式場景,自增主鍵容易被探知到系統業務量等。由此可見在系統業務量較小,並發量不大時使用自增主鍵不失為一種較好的選擇,但是當面對高並發、分布式需求時,使用自增主鍵會存在較大的瓶頸。
  • 【系統架構】MySQL的自增ID用完了,插入數據會出現什麼問題?
    一般情況下每一個主鍵在 MySQL 中只要定義了這個數的字節長度,那麼就會有上限。數據表定義的自增 ID,如果達到上限之後。再申請下一個 ID 的時候,獲得到的值將保持不變。下面通過實驗來驗證一下:我們創建了一個表test,同時將自增id的初始值設置為4294967295,
  • 不要再使用uuid作為MySQL的主鍵了
    前言在mysql中設計表的時候,mysql官方推薦不要使用uuid或者不連續不重複的雪花id(long形且唯一,單機遞增),而是推薦連續自增的主鍵id,官方的推薦是auto_increment>2.1.使用自增id的內部結構自增的主鍵的值是順序的
  • 為什麼MySQL不推薦使用uuid或者雪花id作為主鍵?
    前言在mysql中設計表的時候,mysql官方推薦不要使用uuid或者不連續不重複的雪花id(long形且唯一,單機遞增),而是推薦連續自增的主鍵id,官方的推薦是auto_increment,那麼為什麼不建議採用uuid,使用uuid究竟有什麼壞處?
  • 知道為什麼MySQL不推薦使用uuid或者雪花id作為主鍵?
    中設計表的時候,mysql官方推薦不要使用uuid或者不連續不重複的雪花id(long形且唯一,單機遞增),而是推薦連續自增的主鍵id,官方的推薦是auto_increment,那麼為什麼不建議採用uuid,使用uuid究竟有什麼壞處?
  • hibernate主鍵生成策略
    <id> 元素內部 提供 <generator> 元素, 有class屬性,指定數據表主鍵生成策略第一種 : increment 代理主鍵 流水號, 流水號自增由 hibernate框架完成 , 原理 select max(id) , +1 作為新插入記錄的
  • mysql為什麼不推薦使用uuid或者雪花id作為主鍵
    帶著疑問,我們來探討一下這個問題: 二: 使用uuid和自增id的索引結構對比2.1:使用自增id的內部結構 自增的主鍵的值是順序的結論:使用innodb應該儘可能的按主鍵的自增順序插入,並且儘可能使用單調的增加的聚簇鍵的值來插入新行2.3:使用自增
  • 老大問:建表為啥還設置個自增 id ?用流水號當主鍵不正好麼
    設置成主鍵,這樣就不用 id 了,還減少一次回表查詢? 我:…… (說的好像很有道理,咱也不敢說話。) 老大:既然他們規定了,那你回去查一下為什麼要設計個自增 id ? 我:掏出小本本(回去查資料~)。
  • Mybatis 插入數據後返回自增主鍵ID
    在映射器中配置獲取記錄主鍵值在xml中 insert 標籤中定義 :* useGeneratedKeys為true,用來設置返回主鍵id的值,* keyProperty 代表資料庫記錄主鍵欄位* keyColumn 代表
  • MySQL中的6種約束,你掌握了幾種?
    在建立數據表的時候,一般情況下,為了方便更快地查找表中的記錄,都會要求在表中設置一個「主鍵」。」主鍵「是表裡面的一個特殊欄位,這個欄位能夠唯一標識該表中的每條信息。主鍵分為「單欄位主鍵」和「多欄位聯合主鍵」,並且在使用主鍵的時候需要注意以下幾個點:一個表只能定義一個主鍵;主鍵值必須唯一標識表中的每一行,並且不能出現的情況,即表中不能存在有相同主鍵的兩行或兩行以上數據,嚴格遵守唯一性原則;一個欄位名只能在聯合主鍵欄位表中出現一次
  • Mysql 分頁查詢的誤區,你一定遇到過
    > select * from employees limit 10000,10;上面的查詢你肯定以為mysql直接從表中取出10001行開始的10行記錄。
  • MySQL性能優化—實踐篇2
    對比兩個排序模式,單路排序會把所有需要查詢的欄位都放到 sort_buffer 中,而雙路排序只會把主鍵和需要排序的欄位放到 sort_buffer 中進行排序,然後再通過主鍵回到原表查詢需要的欄位。常見的分頁場景優化技巧根據自增且連續的主鍵排序的分頁查詢