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

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

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è)務(wù)設(shè)計(jì)依賴于自增主鍵的連續(xù)性,這個(gè)設(shè)計(jì)假設(shè)自增主鍵是連續(xù)的。但實(shí)際上,這樣的假設(shè)是錯(cuò)的,因?yàn)樽栽鲋麈I不能保證連續(xù)遞增。

一、自增值的屬性特征:

1. 自增主鍵值是存儲(chǔ)在哪的?

MySQL5.7版本

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

MySQL8.0之后版本

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

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

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

2. 自增主鍵值的修改機(jī)制?

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

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

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

根據(jù)要插入的值和當(dāng)前自增值的大小關(guān)系,自增值的變更結(jié)果也會(huì)有所不同。假設(shè),某次要插入的值是 X,當(dāng)前的自增值是 Y。

如果 X

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

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

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

insertintotvalues(null,1,1);

流程圖如下所示

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

流程步驟:

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

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

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

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

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

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

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

當(dāng)我執(zhí)行以下SQL語句時(shí)

insertintotvalues(null,1,1);

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

當(dāng)我們第二次在執(zhí)行以下SQL語句時(shí),就會(huì)出現(xiàn)錯(cuò)誤。因?yàn)槲覀儽碇衏字段是唯一索引,會(huì)出現(xiàn)Duplicate key error錯(cuò)誤導(dǎo)致新增失敗。

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

例如:

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

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

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

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

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

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

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

其實(shí)事務(wù)回滾原理也和上面一樣,都是因?yàn)楫惓?dǎo)致新增失敗,但是自增值沒有進(jìn)行回退。

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

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

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

1 個(gè)用完以后,這個(gè)語句第二次申請自增 id,會(huì)分配 2 個(gè);

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

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

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

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。當(dāng)我們再執(zhí)行 insert into t2 values(null, 5,5),實(shí)際上插入的數(shù)據(jù)就是(8,5,5),出現(xiàn)了自增主鍵不連續(xù)的情況。

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

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

1.什么是自增鎖

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

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

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

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

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

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

間斷模式(Consecutive)

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

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

穿插模式(Interleaved)

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

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

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

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







審核編輯:劉清

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

    關(guān)注

    0

    文章

    42

    瀏覽量

    15246
  • MySQL
    +關(guān)注

    關(guān)注

    1

    文章

    794

    瀏覽量

    26353
  • SQL語句
    +關(guān)注

    關(guān)注

    0

    文章

    19

    瀏覽量

    7018

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

文章出處:【微信號(hào):AndroidPush,微信公眾號(hào):Android編程精選】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏

    評論

    相關(guān)推薦

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

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

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

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

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

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

    Python常用運(yùn)算寫法

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

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

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

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

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

    關(guān)于MySQL的基礎(chǔ)知識(shí)簡析

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

    21個(gè)MySQL表設(shè)計(jì)的經(jīng)驗(yàn)準(zhǔn)則

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

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

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

    主鍵不用隨機(jī)字符串用什么?主鍵?

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

    線上MySQLid用盡怎么辦?

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

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

    如果你的業(yè)務(wù)設(shè)計(jì)依賴于主鍵連續(xù)性,這個(gè)設(shè)計(jì)假設(shè)主鍵
    的頭像 發(fā)表于 06-11 11:35 ?512次閱讀
    <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的機(jī)制不同在mysql的索引結(jié)構(gòu)以及優(yōu)缺點(diǎn)

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

    MySQL索引的常用知識(shí)點(diǎn)

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

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

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