Mysql自增id用完了,到底會不會報錯?

2021-02-20 架構師之巔

前些天有個粉絲在群裡發了一張圖片,成功引起了我的注意,圖片如下:


大致內容是在mysql中,一個表的自增id用完了,繼續插入到底會不會報錯?說實話,工作這麼多年,我還真沒遇到這種問題,也沒太想過,我的第一反應應該是會報錯,否則mysql也不會有那麼多類型和長度的限制;但是同時我也很疑惑,說不定mysql有什麼保護機制,可以自動升級類型之類的,接下來我將帶領大家去一層層揭開這個疑點。

我們可以想一下,資料庫為什麼需要主鍵?不需要主鍵行不行?資料庫三範式設計中,其中第二範式就明確要求表中每一行數據都需要被維一區分,這個時候主鍵就很必要了,比如一張顧客表,可以通過顧客id當作主鍵,訂單表可以通過訂單id當作主鍵,只要你認為能唯一標示這張表就可以;雖然我們並不總是都需要主鍵,但大多數資料庫設計人員都應保證他們創建的每個表有一個主鍵,以便於以後數據操縱和管理表中的任何列都可以作為主鍵,只要它滿足以下條件:

1、任何兩行都不具有相同的主鍵值

2、每個行都必須具有一個主鍵值(主鍵列不允許NULL值)

主鍵的底層是用索引來實現的,而索引主要分為聚簇索引和非聚簇索引,接下來我來介紹一下聚簇索引和非聚簇索引的區別。

聚簇索引

聚簇索引不是一種單獨的索引類型,而是一種數據存儲方式。innodb的聚簇索引實際上在同一個結構中保存了B-tree索引和數據行。當表有聚簇索引時,數據行實際上是存儲在索引的葉子頁中。聚簇:表示數據行和相鄰的鍵值緊湊地存儲在一起。一個表只能有一個聚簇索引,聚簇索引如何存放記錄如圖:

聚簇索引的優點:

1.可以把相關數據保存在一起

2.數據訪問更快(聚集索引將索引和數據保存在同一個b-tree中)

3.使用覆蓋索引掃描的查詢可以直接使用頁節點中的主鍵值

聚簇索引的缺點:

1、聚簇數據提高了IO性能,如果數據全部放在內存中,則訪問的順序就沒那麼重要了

2、插入速度嚴重依賴插入順序。按主鍵的順序插入是速度最快的。但如果不是按照主鍵順序加載數據,則需在加載完成後最好使用optimize table重新組織一下表

3、更新聚簇索引列的代價很高。因為會強制innod將每個被更新的行移動到新的位置

4、基於聚簇索引的表在插入新行,或主鍵被更新導致需要移動行的時候,可能面臨頁分裂的問題。頁分裂會導致表佔用更多的磁碟空間。

5、聚簇索引可能導致全表掃描變慢,尤其是行比較稀疏,或由於頁分裂導致數據存儲不連續時。

非聚簇索引,又叫二級索引。二級索引的葉子節點中保存的不是指向行的物理指針,而是行的主鍵值。當通過二級索引查找行,存儲引擎需要在二級索引中找到相應的葉子節點,獲得行的主鍵值,然後使用主鍵去聚簇索引中查找數據行,這需要兩次B-Tree查找。

下表代表聚簇索引和非聚簇索引表的分布情況:

    上一段我們提到,mysql的主鍵是使用的是聚簇索引,如果使用非自增主鍵(如果身份證號或學號等),由於每次插入主鍵的值近似於隨機,因此每次新紀錄都要被插到現有索引頁得中間某個位置,此時MySQL不得不為了將新記錄插到合適位置而移動數據,甚至目標頁面可能已經被回寫到磁碟上而從緩存中清掉,此時又要從磁碟上讀回來,這增加了很多開銷,同時頻繁的移動、分頁操作造成了大量的碎片,得到了不夠緊湊的索引結構,後續不得不通過OPTIMIZE TABLE來重建表並優化填充頁面。

    如果表使用自增主鍵,那麼每次插入新的記錄,記錄就會順序添加到當前索引節點的後續位置,當一頁寫滿,就會自動開闢一個新的頁。總的來說就是可以提高查詢和插入的性能。

對InnoDB來說

1: 主鍵索引既存儲索引值,又在葉子節點中存儲行的數據,也就是說數據文件本身就是按照b+樹方式存放數據的。

2: 如果沒有定義主鍵,則會使用非空的UNIQUE鍵做主鍵 ; 如果沒有非空的UNIQUE鍵,則系統生成一個6位元組的rowid做主鍵;

聚簇索引中,N行形成一個頁(一頁通常大小為16K)。如果碰到不規則數據插入時,為了保持B+樹的平衡,會造成頻繁的頁分裂和頁旋轉,插入速度比較慢。所以聚簇索引的主鍵值應儘量是連續增長的值,而不是隨機值(不要用隨機字符串或UUID)。

故對於InnoDB的主鍵,儘量用整型,而且是遞增的整型。如果沒有特別的需要,請永遠使用一個與業務無關的自增欄位作為主鍵吧。

實踐是檢驗真理的唯一標準,既然對這塊知識點不是很清楚,那就動手做一下實驗。首先,我創建一張表,這個表只有1個欄位,分別是id , 如下:

create table t1(
 `id` int(10) unsigned primary key not null auto_increment
)  engine=InnoDB charset=utf8

我們定義這個表中的id 是 unsigned ,最大可以達到2的32次冪,如果這樣測試下來,半天也插不完,所以這裡有個小技巧,可以在創建表的時候,直接聲明auto_increment的初始值,我們修改下表結構:

create table t1(
 `id` int(10) unsigned primary key not null auto_increment
) engine=InnoDB auto_increment=4294967295 charset=utf8

接下來,我們嘗試插入一條數據,得到了下面的結果。

mysql> insert into t1 values();
ERROR 2006 (HY000): MySQL server has gone away
No connection. Trying to reconnect...
Connection id:    8
Current database: demo

ERROR 1062 (23000): Duplicate entry '4294967295' for key 'PRIMARY'

說明,當再次插入時,使用的自增id還是4294967295,報主鍵衝突的錯誤。當然4294967295可以應付大部分的場景了,如果你的服務會經常性的插入,修改還是會有用完的風險,此時建議使用bigint

       資料庫系統的設計者巧妙利用了磁碟預讀原理,將一個節點的大小設為等於一個頁,這樣每個節點只需要一次I/O就可以完全載入。為了達到這個目的,在實際實現B+Tree還需要使用如下技巧:每次新建節點時,直接申請一個頁的空間,這樣就保證一個節點物理上也存儲在一個頁裡,加之計算機存儲分配都是按頁對齊的,就實現了一個node只需一次I/O。B+Tree的節點都是按照鍵值的大小順序存放的,葉節點之間也通過指針連接起來,為了提高取數據時的效率。

      使用自增id當主鍵,那麼每次插入新的記錄,記錄就會順序添加到當前索引節點的後續位置,當一頁寫滿,就會自動開闢一個新的頁。總的來說就是可以提高查詢和插入的性能。

相關焦點

  • MySQL性能優化
    如果把慢查詢的sql記錄到我們的一個日誌中在默認情況下,低版本的mysql不會記錄慢查詢,需要在啟動mysql時候,指定記錄慢查詢才可以bin\mysqld.exe - -safe-mode  - -slow-query-log [mysql5.5 可以在my.ini指定]bin\mysqld.exe –log-slow-queries
  • Python連接MySQL資料庫方法介紹(超詳細!手把手項目案例操作)
    執行結果如下:('a', '趙大', '16')('b', '錢二', '16')mysql.connectormysql-connector-python:是MySQL官方的純Python驅動;mysql.connector安裝安裝pip install mysql查看版本pip show
  • MySQL 的 in 查詢不走索引?我拿什麼拯救你!
    我想證明我是錯的,於是我到網上搜索了非常多的文章,什麼 MySQL 優化實戰,MySQL 軍規 36 條,30條SQL優化軍規,SQL語句優化原則,mysql語句優化建議,資料庫查詢優化方法總結等等有非常多的文章在描述,MySQL 中 in 查詢不走索引。 這些文章當中有些是 2018 年才發出來的,完全屬於誤導讀者。今天我們一起來看看 MySQL 的 in 查詢到底走不走索引?
  • mysql指令、數據類型、表結構、約束學習記錄
    mysql常用口令--修改用戶密碼的命令mysqladmin -uroot -proot123 password mysql123--登錄mysql資料庫的命令mysql -uroot-proot123--顯示資料庫的命令show databases;--使用資料庫的命令use mysql;--顯示當前連接的資料庫select database
  • 在mysql中如何刪除記錄?delete關鍵字了解一下
    在上一篇文章中我們學習了如何更新mysql中的數據內容,用到的是update這個關鍵字,今天我們要學習的是如何讓在mysql中刪除記錄,也就是從箱子裡面拿走東西,用到的關鍵字是delete這個關鍵字,下面我們就通過一個例子來了解一下。
  • 圖解MySQL索引——B-Tree(B+Tree)
    非聚簇索引:不是聚簇索引,就是非聚簇索引四、索引的底層實現mysql默認存儲引擎innodb只顯式支持B-Tree( 從技術上來說是B+Tree)索引,對於頻繁訪問的表,innodb會透明建立自適應hash索引,即在B樹索引基礎上建立hash索引,可以顯著提高查找效率,對於客戶端是透明的
  • xml 映射mysql - CSDN
    Maven會將此文件夾中的所有文件視為資源文件,並自動將其複製到輸出類。-- MySQL database driver --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.9</version> </dependency
  • MySQL如何計算統計redo log大小
    USE mysqls;CREATETABLEIFNOTEXISTS innodb_log_size_his( log_id INT AUTO_INCREMENT PRIMARYKEY COMMENT '日誌編號', log_date DATETIME COMMENT '記錄當前數據的時間', log_size
  • MySQL中order by與limit不要一起用!
    後來百度了一下,如果 order by 的列有相同的值時,MySQL 會隨機選取這些行,為了保證每次都返回的順序一致可以額外增加一個排序欄位(比如:id),用兩個欄位來儘可能減少重複的概率。於是,改成 order by status,id:
  • 面試官:分庫分表後,id主鍵如何處理?
    作為一名java程式設計師,求職面試時,關於主鍵id的問題時常會遇到,張工是一名java程式設計師,最近到某知名網際網路公司面試,面試官提出這樣的一個問題:分庫分表後,id主鍵如何處理?張工一時間沒有回答上來,面試官:你都工作三年了,怎麼沒有使用過雪花算法啊。
  • mysql資料庫行列矩陣調換位置(行與列調換)
    表(stu_bysjytj)的數據結構如下:解決方案如下:以下是mysql資料庫的具體操作代碼:解釋:id、leibie、jiangong、yuanlin、zaojia、zhuangshi、wuye、jiudian、xueqian、heji為視圖的欄位第一行:id=1,leibie=biye_num ……id=2,leibie=jiuye_num……id=3 leibie=w_jiuye_num
  • MySQL怎麼刪除#sql開頭的臨時表
    注意: 此類表空間文件不能直接rm -f的方式物理刪除,因為該信息記錄在ibdata的共享表空間裡,直接刪除後,後續實例重啟時會出現錯誤。3. 處理方法3.1   同時存在.frm 和.ibd名稱相同的文件如果 #sql-*.ibd 和 #sql-*.frm兩個文件都存在數據目錄裡的話,可以直接drop table。
  • 資料庫軟體架構,到底要設計些什麼?
    數據的冗餘,會帶來一個副作用:一致性問題。如何保證資料庫「讀」高可用?冗餘讀庫。上圖是很多網際網路公司mysql的架構,寫仍然是單點,不能保證寫高可用。如何保證資料庫「寫」高可用?冗餘寫庫。雙寫同步,數據可能衝突(例如「自增id」同步衝突)。
  • MySQL自定義排序
    於是想到,java的集合自定義排序Collections.sort(List list) ×,用戶這麼多,不行,不能使用。還是得再新增一個排序欄位???再想想,於是想到,既然java都有自定義排序,那麼sql應該也有吧。果然,搜了搜,真的有。
  • 免安裝版MySQL操作步驟
    1、 修改mysql安裝目錄下的my.ini文件a) 將Mysql的壓縮包先解壓,解壓後mysql安裝目錄下有如下的文件和文件夾:b) 打開my.ini文件(可以用記事本打開)c) 修改my.ini文件中basedir的值改為mysql的安裝目錄d) 修改my.ini文件中datadir的值改為mysql中data文件夾的目錄2、 配置環境變量
  • 電子數據取證之MySQL資料庫刪除數據的恢復指南
    公檢法部門在處理涉黃、詐騙的案件時,常常會遇到對涉案網站、論壇的伺服器進行取證,有時嫌疑人為了毀滅罪證,故意刪除數據,這就涉及到對MySQL資料庫進行數據恢復、固定和取證。效率源科技的技術大咖針對一線辦案人員遇到的痛點,寫了這篇MySQL資料庫刪除數據的恢復指南,希望對辦案人員有所啟發。
  • Mysql數據誤刪除快速回滾
    作者 | Video++極鏈科技OPSTeam整理 | 包包在資料庫操作中,難免會因為各種各樣的原因對數據造成損壞,這個時候就需要對資料庫快速恢復。傳統的方法會先恢復mysql備份,再去用mysqlbinlog抽取指定時間點的日誌,再恢復,這樣的操作比較耗時,容易出錯,那有沒有一種工具可以快速把誤刪除的操作SQL逆過來,然後重新插入誤刪除的數據呢?binlog2sql,就是一個很好的應用,它可以從MySQL binlog解析出SQL,根據不同選項,你可以得到原始SQL、回滾SQL、去除主鍵的INSERT SQL等。
  • MySQL 5.7.11 版本發布
    好在拉德納推出了Windows 10的1年免費升級方案,帶動了大批用戶的升級,Office 365的推出也找到了軟體更新與付費之間的平衡。5.7.11版本修復了一些bug,具體可見:http://dev.mysql.com/doc/relnotes/mysql/5.7/en/news-5-7-11.html。
  • MySQL基於MHA的FailOver過程
    7.修復故障主節點(k8s可以實現節點自愈)MHA的Failover如何實現從啟動--->故障--->轉移---->業務恢復1.MHA通過master_manager腳本啟動MHA功能2.在manager啟動之前,會自動調用檢查