0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

MySQL自增主鍵一定是連續(xù)的嗎?

Android編程精選 ? 來源:CSDN ? 2023-03-21 16:55 ? 次閱讀

測試環(huán)境:

MySQL版本:8.0

數(shù)據(jù)庫表:T (主鍵id,唯一索引c,普通字段d)

2f50432e-ba24-11ed-bfe3-dac502259ad0.png

如果你的業(yè)務設計依賴于自增主鍵的連續(xù)性,這個設計假設自增主鍵是連續(xù)的。但實際上,這樣的假設是錯的,因為自增主鍵不能保證連續(xù)遞增。

一、自增值的屬性特征:

1. 自增主鍵值是存儲在哪的?

MySQL5.7版本

在 MySQL 5.7 及之前的版本,自增值保存在內存里,并沒有持久化。每次重啟后,第一次打開表的時候,都會去找自增值的最大值 max(id),然后將 max(id)+1 作為這個表當前的自增值。

MySQL8.0之后版本

在 MySQL 8.0 版本,將自增值的變更記錄在了 redo log 中,重啟的時候依靠 redo log 恢復重啟之前的值。

可以通過看表詳情查看當前自增值,以及查看表參數(shù)詳情AUTO_INCREMENT值(AUTO_INCREMENT就是當前數(shù)據(jù)表的自增值)

2f7fe2e6-ba24-11ed-bfe3-dac502259ad0.png

2. 自增主鍵值的修改機制?

在表t中,我定義了主鍵id為自增值,在插入一行數(shù)據(jù)的時候,自增值的行為如下:

如果插入數(shù)據(jù)時 id 字段指定為 0、null 或未指定值,那么就把這個表當前的 AUTO_INCREMENT 值填到自增字段;

如果插入數(shù)據(jù)時 id 字段指定了具體的值,就直接使用語句里指定的值。

根據(jù)要插入的值和當前自增值的大小關系,自增值的變更結果也會有所不同。假設,某次要插入的值是 X,當前的自增值是 Y。

如果 X

如果 X≥Y,就需要把當前自增值修改為新的自增值。

二、新增語句自增主鍵是如何變化的:

我們執(zhí)行以下SQL語句,來觀察自增主鍵是如何進行變化的

insertintotvalues(null,1,1);

流程圖如下所示

2f9326a8-ba24-11ed-bfe3-dac502259ad0.png

流程步驟:

AUTO_INCREMENT=1 (表示下一次插入數(shù)據(jù)時,如果需要自動生成自增值,會生成 id=1。)

insert into t values(null, 1, 1) (執(zhí)行器調用 InnoDB 引擎接口寫入一行,傳入的這一行的值是 (0,1,1))

get AUTO_INCREMENT=1 (InnoDB 發(fā)現(xiàn)用戶沒有指定自增 id 的值,獲取表 t 當前的自增值 1 )

AUTO_INCREMENT=2 insert into t values(1, 1, 1) (將傳入的行的值改成 (1,1,1),并把自增值改為2)

insert (1,1,1) 執(zhí)行插入操作,至此流程結束

大家可以發(fā)現(xiàn),在這個流程當中是先進行自增值的+1,在進行新增語句的執(zhí)行的。大家可以發(fā)現(xiàn)這個操作并沒有進行原子操作,如果SQL語句執(zhí)行失敗,那么自增是不是就不會連續(xù)了呢?

三、自增主鍵值不連續(xù)情況:(唯一主鍵沖突)

當我執(zhí)行以下SQL語句時

insertintotvalues(null,1,1);

第一次我們可以進行新增成功,根據(jù)自增值的修改機制。如果插入數(shù)據(jù)時 id 字段指定為 0、null 或未指定值,那么就把這個表當前的 AUTO_INCREMENT 值填到自增字段;

當我們第二次在執(zhí)行以下SQL語句時,就會出現(xiàn)錯誤。因為我們表中c字段是唯一索引,會出現(xiàn)Duplicate key error錯誤導致新增失敗。

2fc88dca-ba24-11ed-bfe3-dac502259ad0.png

例如:

AUTO_INCREMENT=2 (表示下一次插入數(shù)據(jù)時,如果需要自動生成自增值,會生成 id=2。)

insert into t values(null, 1, 1) (執(zhí)行器調用 InnoDB 引擎接口寫入一行,傳入的這一行的值是 (0,1,1))

get AUTO_INCREMENT=2 (InnoDB 發(fā)現(xiàn)用戶沒有指定自增 id 的值,獲取表 t 當前的自增值 2 )

AUTO_INCREMENT=3 insert into t values(2, 1, 1) (將傳入的行的值改成 (2,1,1),并把自增值改為3)

insert (2,1,1) 執(zhí)行插入操作,由于已經(jīng)存在 c=1 的記錄,所以報 Duplicate key error,語句返回。

可以看到,這個表的自增值改成 3,是在真正執(zhí)行插入數(shù)據(jù)的操作之前。這個語句真正執(zhí)行的時候,因為碰到唯一鍵 c 沖突,所以 id=2 這一行并沒有插入成功,但也沒有將自增值再改回去。所以,在這之后,再插入新的數(shù)據(jù)行時,拿到的自增 id 就是 3。也就是說,出現(xiàn)了自增主鍵不連續(xù)的情況。

四、自增主鍵值不連續(xù)情況:(事務回滾)

其實事務回滾原理也和上面一樣,都是因為異常導致新增失敗,但是自增值沒有進行回退。

五、自增主鍵值不連續(xù)情況:(批量插入)

批量插入數(shù)據(jù)的語句,MySQL 有一個批量申請自增 id 的策略:

語句執(zhí)行過程中,第一次申請自增 id,會分配 1 個;

1 個用完以后,這個語句第二次申請自增 id,會分配 2 個;

2 個用完以后,還是這個語句, 第三次申請自增 id,會分配 4 個;

依此類推,同一個語句去申請自增 id,每次申請到的自增 id 個數(shù)都是上一次的兩倍。

執(zhí)行以下SQL語句(在表t中先新增了4條數(shù)據(jù),在創(chuàng)建表tt把表t數(shù)據(jù)進行批量新增)

insertintotvalues(null,1,1);
insertintotvalues(null,2,2);
insertintotvalues(null,3,3);
insertintotvalues(null,4,4);
createtablettliket;
insertintott(c,d)selectc,dfromt;

insertintottvalues(null,5,5);

第一次申請到了 id=1,第二次被分配了 id=2 和 id=3, 第三次被分配到 id=4 到 id=7。當我們再執(zhí)行 insert into t2 values(null, 5,5),實際上插入的數(shù)據(jù)就是(8,5,5),出現(xiàn)了自增主鍵不連續(xù)的情況。

2fdb3646-ba24-11ed-bfe3-dac502259ad0.png

六、自增主鍵值的優(yōu)化

1.什么是自增鎖

自增鎖是一種比擬非凡的表級鎖。并且在事務向蘊含了 AUTO_INCREMENT 列的表中新增數(shù)據(jù)時就會去持有自增鎖,假如事務 A 正在做這個操作,如果另一個事務 B 嘗試執(zhí)行 INSERT語句,事務 B 會被阻塞住,直到事務 A 開釋自增鎖。

2.自增鎖有哪些優(yōu)化

在 MySQL 5.0 版本的時候,自增鎖的范圍是語句級別。也就是說,如果一個語句申請了一個表自增鎖,這個鎖會等語句執(zhí)行結束以后才釋放。顯然,這樣設計會影響并發(fā)度。在MySQL 5.1.22 版本引入了一個新策略,新增參數(shù) innodb_autoinc_lock_mode,默認值是 1。

傳統(tǒng)模式(Traditional)

這個參數(shù)的值被設置為 0 時,表示采用之前 MySQL 5.0 版本的策略,即語句執(zhí)行結束后才釋放鎖;

傳統(tǒng)模式他可以保證數(shù)據(jù)一致性,但是如果有多個事務并發(fā)的執(zhí)行 INSERT 操作,AUTO-INC的存在會使得 MySQL 的性能略有降落,因為同時只能執(zhí)行一條 INSERT 語句。

間斷模式(Consecutive)

這個參數(shù)的值被設置為 1 時:普通 insert 語句,自增鎖在申請之后就馬上釋放;類似 insert … select 這樣的批量插入數(shù)據(jù)的語句,自增鎖還是要等語句結束后才被釋放;

間斷模式他可以保證數(shù)據(jù)一致性,但是如果有多個事務并發(fā)的執(zhí)行 INSERT 批量操作時,就會進行鎖等待狀態(tài)。如果我們業(yè)務插入數(shù)據(jù)量很大時,這個時候MySQL的性能就會大大下降。

穿插模式(Interleaved)

這個參數(shù)的值被設置為 2 時,所有的申請自增主鍵的動作都是申請后就釋放鎖。

穿插模式他沒有進行任何的上鎖設置。在一定情況下是保證了MySQL的性能,但是他無法保證數(shù)據(jù)的一致性。如果我們在穿插模式下進行主從復制時,如果你的binlog格式不是row格式,主從復制就會出現(xiàn)不一致。

七、MySQL8.0做了哪些優(yōu)化

在MySQL8.0之后版本,已經(jīng)默認設置為 innodb_autoinc_lock_mode=2 , binlog_format=row.。這樣更有利與我們在 insert … select 這種批量插入數(shù)據(jù)的場景時,既能提升并發(fā)性,又不會出現(xiàn)數(shù)據(jù)一致性問題。







審核編輯:劉清

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權轉載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • Auto
    +關注

    關注

    0

    文章

    41

    瀏覽量

    15237
  • MySQL
    +關注

    關注

    1

    文章

    789

    瀏覽量

    26283
  • SQL語句
    +關注

    關注

    0

    文章

    19

    瀏覽量

    7015

原文標題:被問懵了:MySQL 自增主鍵一定是連續(xù)的嗎?

文章出處:【微信號:AndroidPush,微信公眾號:Android編程精選】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    怎么簡單實現(xiàn)由Labview讀取的串口數(shù)據(jù)寫入mysql5.7數(shù)據(jù)庫中?

    怎么簡單實現(xiàn)由Labview讀取的串口數(shù)據(jù)寫入mysql5.7數(shù)據(jù)庫中? 已實現(xiàn):串口數(shù)據(jù)的接收處理 mysql5.7的安裝(已測試數(shù)據(jù)庫正常運行) 愿付費解決此問題(QQ:8
    發(fā)表于 01-11 22:05

    #硬聲創(chuàng)作季 【MySQL調優(yōu)】為什么推薦使用整型的主鍵而不是UUID

    數(shù)據(jù)庫MySQL
    Mr_haohao
    發(fā)布于 :2022年09月14日 07:41:14

    阿里云mysql數(shù)據(jù)庫怎么設置主鍵和時間格式怎么顯示時分秒?

    `需要將測試的數(shù)據(jù)保存到阿里云mysql數(shù)據(jù)庫上,利用NI的數(shù)據(jù)庫工具包怎么創(chuàng)建表實現(xiàn)主鍵?還有保存的時間數(shù)據(jù)只顯示日期,不顯示時分秒(用DB Tools Format Datet
    發(fā)表于 11-13 10:39

    Python常用運算寫法

    在學習任何種編程語言,運算方法的學習是不可避免的,其中運算符++的使用也是其中的重點,很多人容易弄不明白其用法,尤其是在Python中,其用法更加的不同!我們可以寫個實例來說明
    發(fā)表于 04-09 17:45

    labview向oracle插入數(shù)據(jù),怎樣可以主鍵1?如果不插入主鍵的字段,會報插入的數(shù)目與表中的數(shù)據(jù)不相等

    本帖最后由 電子人steve 于 2018-5-23 20:30 編輯 labview向oracle數(shù)據(jù)庫插入數(shù)據(jù)時,怎樣可以主鍵1啊,服務器數(shù)據(jù)庫表中設置了
    發(fā)表于 05-23 18:53

    MySQL表分區(qū)類型及介紹

    表分區(qū)是將個表的數(shù)據(jù)按照一定規(guī)則水平劃分成不同的邏輯塊,并分別進行物理存儲,這個規(guī)則就叫做分區(qū)函數(shù),可以有不同的分區(qū)規(guī)則。通過show plugins語句查看當前MySQL是否支持表分區(qū)功能
    發(fā)表于 06-29 16:31

    關于MySQL的基礎知識簡析

    系統(tǒng)環(huán)境MAC OS 10.10MySQL版本,5.7.9Mac 安裝mysql很簡單,官網(wǎng)下載安裝包,雙擊安裝就可以了,有幾個地方需要注意在Mac下用DMG包新安裝mysql,在安裝完畢最后
    發(fā)表于 11-03 11:50

    21個MySQL表設計的經(jīng)驗準則

    主鍵設計的話,最好不要與業(yè)務邏輯有所關聯(lián)。有些業(yè)務上的字段,比如身份證,雖然是唯的,些開發(fā)者喜歡用它來做主鍵,但是不是很建議哈。主鍵最好
    的頭像 發(fā)表于 01-12 10:07 ?512次閱讀

    MySQL主鍵一定是連續(xù)的嗎?

    眾所周知,主鍵可以讓聚集索引盡量地保持遞增順序插入,避免了隨機查詢,從而提高了查詢效率
    的頭像 發(fā)表于 02-20 18:06 ?632次閱讀

    主鍵不用隨機字符串用什么?主鍵?

    主鍵不用隨機字符串用什么?主鍵?主鍵就是最佳
    的頭像 發(fā)表于 05-09 09:04 ?502次閱讀
    <b class='flag-5'>主鍵</b>不用隨機字符串用什么?<b class='flag-5'>主鍵</b><b class='flag-5'>自</b><b class='flag-5'>增</b>?

    線上MySQLid用盡怎么辦?

    MySQLid都定義了初始值,然后不斷加步長。雖然自然數(shù)沒有上限,但定義了表示這個數(shù)的字節(jié)長度,計算機存儲就有上限。
    的頭像 發(fā)表于 05-22 10:23 ?421次閱讀
    線上<b class='flag-5'>MySQL</b>的<b class='flag-5'>自</b><b class='flag-5'>增</b>id用盡怎么辦?

    MySQL主鍵一定是連續(xù)的嗎?

    如果你的業(yè)務設計依賴于主鍵連續(xù)性,這個設計假設主鍵
    的頭像 發(fā)表于 06-11 11:35 ?492次閱讀
    <b class='flag-5'>MySQL</b><b class='flag-5'>自</b><b class='flag-5'>增</b><b class='flag-5'>主鍵</b><b class='flag-5'>一定是</b><b class='flag-5'>連續(xù)</b>的嗎?

    id的機制不同在mysql的索引結構以及優(yōu)缺點

    的時候,mysql官方推薦不要使用uuid或者不連續(xù)不重復的雪花id(long形且唯,單機遞增),而是推薦連續(xù)
    的頭像 發(fā)表于 06-30 10:19 ?716次閱讀
    id的機制不同在<b class='flag-5'>mysql</b>的索引結構以及優(yōu)缺點

    MySQL索引的常用知識點

    索引結構:B+樹 索引其實是種數(shù)據(jù)結構 注意B+樹是MySQL,索引默認的結構;張表至少有個索引(主鍵索引),是可以有多個索引的
    的頭像 發(fā)表于 09-30 16:43 ?374次閱讀

    主鍵去哪了?---次開發(fā)過程中的思考

    TABLE `example_table` ( `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主鍵
    的頭像 發(fā)表于 09-05 14:12 ?98次閱讀
    <b class='flag-5'>自</b><b class='flag-5'>增</b><b class='flag-5'>主鍵</b>去哪了?---<b class='flag-5'>一</b>次開發(fā)過程中的思考