免费爱碰视频在线观看,九九精品国产屋,欧美亚洲尤物久久精品,1024在线观看视频亚洲

      數(shù)據(jù)庫主鍵一定要自增嗎?有哪些場景不建議自增?

      數(shù)據(jù)庫主鍵一定要自增嗎?有哪些場景不建議自增?

      我們平時建表的時候,一般會像下面這樣。

      CREATE TABLE `user` ( `id` int NOT NULL AUTO_INCREMENT COMMENT ‘主鍵’, `name` char(10) NOT NULL DEFAULT ” COMMENT ‘名字’, PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

      出于習(xí)慣,我們一般會加一列id作為主鍵,而這個主鍵一般邊上都有個AUTO_INCREMENT, 意思是這個主鍵是自增的。自增就是i++,也就是每次都加1。

      但問題來了。

      主鍵id不自增行不行?

      為什么要用自增id做主鍵?

      離譜點,沒有主鍵可以嗎?

      什么情況下不應(yīng)該自增?

      被這么一波追問,念頭都不通達了?

      這篇文章,我會嘗試回答這幾個問題。

      主鍵不自增行不行

      當(dāng)然是可以的。比如我們可以把建表sql里的AUTO_INCREMENT去掉。

      CREATE TABLE `user` ( `id` int NOT NULL COMMENT ‘主鍵’, `name` char(10) NOT NULL DEFAULT ” COMMENT ‘名字’, PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

      然后執(zhí)行

      INSERT INTO `user` (`name`) VALUES (‘debug’);

      這時候會報錯Field ‘id’ doesn’t have a default value。也就是說如果你不讓主鍵自增的話,那你在寫數(shù)據(jù)的時候需要自己指定id的值是多少,想要主鍵id是多少就寫多少進去,不寫就報錯。

      改成下面這樣就好了

      INSERT INTO `user` (`id`,`name`) VALUES (10, ‘debug’);

      為什么要用自增主鍵

      我們在數(shù)據(jù)庫里保存的數(shù)據(jù)就跟excel表一樣,一行行似的。

      user表

      而在底層,這一行行數(shù)據(jù),就是保存在一個個16k大小的頁里。

      每次都去遍歷所有的行性能會不好,于是為了加速搜索,我們可以根據(jù)主鍵id,從小到大排列這些行數(shù)據(jù),將這些數(shù)據(jù)頁用雙向鏈表的形式組織起來,再將這些頁里的部分信息提取出來放到一個新的16kb的數(shù)據(jù)頁里,再加入層級的概念。于是,一個個數(shù)據(jù)頁就被組織起來了,成為了一棵B+樹索引

      B+樹結(jié)構(gòu)

      而當(dāng)我們在建表sql里聲明了PRIMARY KEY (id)時,mysql的innodb引擎,就會為主鍵id生成一個主鍵索引,里面就是通過B+樹的形式來維護這套索引。

      到這里,我們有兩個點是需要關(guān)注的:

      • 數(shù)據(jù)頁大小是固定16k
      • 數(shù)據(jù)頁內(nèi),以及數(shù)據(jù)頁之間,數(shù)據(jù)主鍵id都是從小到大排序的

      由于數(shù)據(jù)頁大小固定了是16k,當(dāng)我們需要插入一條新的數(shù)據(jù),數(shù)據(jù)頁會被慢慢放滿,當(dāng)超過16k時,這個數(shù)據(jù)頁就有可能會進行分裂。

      針對B+樹葉子節(jié)點,如果主鍵是自增的,那它產(chǎn)生的id每次都比前一次要大,所以每次都會將數(shù)據(jù)加在B+樹尾部,B+樹的葉子節(jié)點本質(zhì)上是雙向鏈表,查找它的首部和尾部,時間復(fù)雜度O(1)。而如果此時最末尾的數(shù)據(jù)頁滿了,那創(chuàng)建個新的頁就好。

      主鍵id自增的情況

      如果主鍵不是自增的,比方說上次分配了id=7,這次分配了id=3,為了讓新加入數(shù)據(jù)后B+樹的葉子節(jié)點還能保持有序,它就需要往葉子結(jié)點的中間找,查找過程的時間復(fù)雜度是O(lgn),如果這個頁正好也滿了,這時候就需要進行頁分裂了。并且頁分裂操作本身是需要加悲觀鎖的??傮w看下來,自增的主鍵遇到頁分裂的可能性更少,因此性能也會更高。

      主鍵id不自增的情況

      沒有主鍵可以嗎

      mysql表如果沒有主鍵索引,查個數(shù)據(jù)都得全表掃描,那既然它這么重要,我今天就不當(dāng)人了,不聲明主鍵,可以嗎?

      嗯,你完全可以不聲明主鍵。

      你確實可以在建表sql里寫成這樣。

      CREATE TABLE `user` ( `name` char(10) NOT NULL DEFAULT ” COMMENT ‘名字’) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

      看起來確實是沒有主鍵的樣子。然而實際上,mysql的innodb引擎內(nèi)部會幫你生成一個名為ROW_ID列,它是個6字節(jié)的隱藏列,你平時也看不到它,但實際上,它也是自增的。有了這層兜底機制保證,數(shù)據(jù)表肯定會有主鍵和主鍵索引。

      跟ROW_ID被隱藏的列還有trx_id字段,用于記錄當(dāng)前這一行數(shù)據(jù)行是被哪個事務(wù)修改的,和一個roll_pointer字段,這個字段是用來指向當(dāng)前這個數(shù)據(jù)行的上一個版本,通過這個字段,可以為這行數(shù)據(jù)形成一條版本鏈,從而實現(xiàn)多版本并發(fā)控制(MVCC)。有沒有很眼熟,這個在之前寫的文章里出現(xiàn)過。

      隱藏的row_id列

      有沒有建議主鍵不自增的場景

      前面提到了主鍵自增可以帶來很多好處,事實上大部分場景下,我們都建議主鍵設(shè)為自增。

      那有沒有不建議主鍵自增的場景呢?

      mysql分庫分表下的id

      聊到分庫分表,那我就需要說明下,遞增和自增的區(qū)別了,自增就是每次都+1,而遞增則是新的id比上一個id要大就行了,具體大多少,沒關(guān)系。

      之前寫過一篇文章提到過,mysql在水平分庫分表時,一般有兩種方式。

      一種分表方式是通過對id取模進行分表,這種要求遞增就好,不要求嚴(yán)格自增,因為取模后數(shù)據(jù)會被分散到多個分表中,就算id是嚴(yán)格自增的,在分散之后,都只能保證每個分表里id只能是遞增的。

      根據(jù)id取模分表

      另一種分表方式是根據(jù)id的范圍進行分表(分片),它會劃出一定的范圍,比如以2kw為一個分表的大小,那0~2kw就放在這張分表中,2kw~4kw放在另一張分表中,數(shù)據(jù)不斷增加,分表也可以不斷增加,非常適合動態(tài)擴容,但它要求id自增,如果id遞增,數(shù)據(jù)則會出現(xiàn)大量空洞。舉個例子,比如第一次分配id=2,第二次分配id=2kw,這時候第一張表的范圍就被打滿了,后面再分配一個id,比如是3kw,就只能存到2kw~4kw(第二張)的分表中。那我在0~2kw這個范圍的分表,也就存了兩條數(shù)據(jù),這太浪費了。

      根據(jù)id范圍分表

      但不管哪種分表方式,一般是不可能繼續(xù)用原來表里的自增主鍵的,原因也比較好理解,原來的每個表如果都從0開始自增的話,那好幾個表就會出現(xiàn)好幾次重復(fù)的id,根據(jù)id唯一的原則,這顯然不合理。

      所以我們在分庫分表的場景下,插入的id都是專門的id服務(wù)生成的,如果是要嚴(yán)格自增的話,那一般會通過redis來獲得,當(dāng)然不會是一個id請求獲取一次,一般會按批次去獲得,比如一次性獲得100個??煊猛炅嗽偃カ@取下一批100個。

      但這個方案有個問題,它嚴(yán)重依賴redis,如果redis掛了,那整個功能就傻了。

      有沒有不依賴于其他第三方組件的方法呢?

      雪花算法

      有,比如Twitter開源的雪花算法。

      雪花算法通過64位有特殊含義的數(shù)字來組成id。

      雪花算法

      首先第0位不用。

      接下來的41位是時間戳。精度是毫秒,這個大小大概能表示個69年左右,因為時間戳隨著時間流逝肯定是越來越大的,所以這部分決定了生成的id肯定是越來越大的。

      再接下來的10位是指產(chǎn)生這些雪花算法的工作機器id,這樣就可以讓每個機器產(chǎn)生的id都具有相應(yīng)的標(biāo)識。

      再接下來的12位,序列號,就是指這個工作機器里生成的遞增數(shù)字。

      可以看出,只要處于同一毫秒內(nèi),所有的雪花算法id的前42位的值都是一樣的,因此在這一毫秒內(nèi),能產(chǎn)生的id數(shù)量就是 2的10次方 2的12次方,大概400w,肯定是夠用了,甚至有點多了。

      但是!

      細心的兄弟們肯定也發(fā)現(xiàn)了,雪花算法它算出的數(shù)字動不動就比上次的數(shù)字多個幾百幾萬的,也就是它生成的id是趨勢遞增的,并不是嚴(yán)格+1自增的,也就是說它并不太適合于根據(jù)范圍來分表的場景。這是個非常疼的問題。

      還有個小問題是,那10位工作機器id,我每次擴容一個工作機器,這個機器怎么知道自己的id是多少呢?是不是得從某個地方讀過來。

      那有沒有一種生成id生成方案,既能讓分庫分表能做到很好的支持動態(tài)擴容,又能像雪花算法那樣并不依賴redis這樣的第三方服務(wù)。

      有。這就是這篇文章的重點了。

      適合分庫分表的uuid算法

      我們可以參考雪花算法的實現(xiàn),設(shè)計成下面這樣。注意下面的每一位,都是十進制,而不是二進制。

      適合分庫分表的uuid算法

      開頭的12位依然是時間,但并不是時間戳,雪花算法的時間戳精確到毫秒,我們用不上這么細,我們改為yyMMddHHmmss,注意開頭的yy是兩位,也就是這個方案能保證到2099年之前,id都不會重復(fù),能用到重復(fù),那也是真·百年企業(yè)。同樣由于最前面是時間,隨著時間流逝,也能保證id趨勢遞增。

      接下來的10位,用十進制的方式表示工作機器的ip,就可以把12位的ip轉(zhuǎn)為10位的數(shù)字,它可以保證全局唯一,只要服務(wù)起來了,也就知道自己的ip是多少了,不需要像雪花算法那樣從別的地方去讀取worker id了,又是一個小細節(jié)。

      在接下來的6位,就用于生成序列號,它能支持每秒鐘生成100w個id。

      最后的4位,也是這個id算法最妙的部分。它前2位代表分庫id,后2位代表分表id。也就是支持一共100*100=1w張分表。

      舉個例子,假設(shè)我只用了1個分庫,當(dāng)我一開始只有3張分表的情況下,那我可以通過配置,要求生成的uuid最后面的2位,取值只能是[0,1,2],分別對應(yīng)三個表。這樣我生成出來的id,就能非常均勻的落到三個分表中,這還順帶解決了單個分表熱點寫入的問題。

      如果隨著業(yè)務(wù)不斷發(fā)展,需要新加入兩張新的表(3和4),同時第0張表有點滿了,不希望再被寫了,那就將配置改為[1,2,3,4],這樣生成的id就不會再插入到對應(yīng)的0表中。同時還可以加入生成id的概率和權(quán)重來調(diào)整哪個分表落更多數(shù)據(jù)。

      有了這個新的uuid方案,我們既可以保證生成的數(shù)據(jù)趨勢遞增,同時也能非常方便擴展分表。非常nice。

      數(shù)據(jù)庫有那么多種,mysql只是其中一種,那其他數(shù)據(jù)庫也是要求主鍵自增嗎?

      tidb的主鍵id不建議自增

      tidb是一款分布式數(shù)據(jù)庫,作為mysql分庫分表場景下的替代產(chǎn)品,可以更好的對數(shù)據(jù)進行分片。

      它通過引入Range的概念進行數(shù)據(jù)表分片,比如第一個分片表的id在0~2kw,第二個分片表的id在2kw~4kw。這其實就是根據(jù)id范圍進行數(shù)據(jù)庫分表。

      它的語法幾乎跟mysql一致,用起來大部分時候是無感的。

      但跟mysql有一點很不一樣的就是,mysql建議id自增,但tidb卻建議使用隨機的uuid。原因是如果id自增的話,根據(jù)范圍分片的規(guī)則,一段時間內(nèi)生成的id幾乎都會落到同一個分片上,比如下圖,從3kw開始的自增uuid,幾乎都落到range 1這個分片中,而其他表卻幾乎不會有寫入,性能沒有被利用起來。出現(xiàn)一表有難,多表圍觀的場面,這種情況又叫寫熱點問題。

      寫熱點問題

      所以為了充分的利用多個分表的寫入能力,tidb建議我們寫入時使用隨機id,這樣數(shù)據(jù)就能被均勻分散到多個分片中。

      用戶id不建議用自增id

      前面提到的不建議使用自增id的場景,都是技術(shù)原因?qū)е碌?,而下面介紹的這個,單純是因為業(yè)務(wù)。

      舉個例子吧。

      如果你能知道一個產(chǎn)品每個月,新增的用戶數(shù)有多少,這個對你來說會是有用的信息嗎?

      對程序員來說,可能這個信息價值不大。

      但如果你是做投資的呢,或者是分析競爭對手呢?

      那反過來。

      如果你發(fā)現(xiàn)你的競爭對手,總能非常清晰的知道你的產(chǎn)品每個月新進的注冊用戶是多少人,你會不會心里毛毛的?

      如果真出現(xiàn)了這問題,先不要想是不是有內(nèi)鬼,先檢查下你的用戶表主鍵是不是自增的。

      如果用戶id是自增的,那別人只要每個月都注冊一個新用戶,然后抓包得到這個用戶的user_id,然后跟上個月的值減一下,就知道這個月新進多少用戶了。

      同樣的場景有很多,有時候你去小店吃飯,發(fā)票上就寫了你是今天的第幾單,那大概就能估計今天店家做了多少單。你是店家,你心里也不舒服吧。

      再比如說一些小app的商品訂單id,如果也做成自增的,那就很容易可以知道這個月成了多少單。

      類似的事情有很多,這些場景都建議使用趨勢遞增的uuid作為主鍵。

      當(dāng)然,主鍵保持自增,但是不暴露給前端,那也行,那前面的話,你當(dāng)我沒說過。

      總結(jié)

      • 建表sql里主鍵邊上的AUTO_INCREMENT,可以讓主鍵自增,去掉它是可以的,但這就需要你在insert的時候自己設(shè)置主鍵的值。
      • 建表sql里的 PRIMARY KEY 是用來聲明主鍵的,如果去掉,那也能建表成功,但mysql內(nèi)部會給你偷偷建一個 ROW_ID的隱藏列作為主鍵。
      • 由于mysql使用B+樹索引,葉子節(jié)點是從小到大排序的,如果使用自增id做主鍵,這樣每次數(shù)據(jù)都加在B+樹的最后,比起每次加在B+樹中間的方式,加在最后可以有效減少頁分裂的問題。
      • 在分庫分表的場景下,我們可以通過redis等第三方組件來獲得嚴(yán)格自增的主鍵id。如果不想依賴redis,可以參考雪花算法進行魔改,既能保證數(shù)據(jù)趨勢遞增,也能很好的滿足分庫分表的動態(tài)擴容。
      • 并不是所有數(shù)據(jù)庫都建議使用自增id作為主鍵,比如tidb就推薦使用隨機id,這樣可以有效避免寫熱點的問題。而對于一些敏感數(shù)據(jù),比如用戶id,訂單id等,如果使用自增id作為主鍵的話,外部通過抓包,很容易可以知道新進用戶量,成單量這些信息,所以需要謹(jǐn)慎考慮是否繼續(xù)使用自增主鍵。
      鄭重聲明:本文內(nèi)容及圖片均整理自互聯(lián)網(wǎng),不代表本站立場,版權(quán)歸原作者所有,如有侵權(quán)請聯(lián)系管理員(admin#wlmqw.com)刪除。
      (0)
      用戶投稿
      上一篇 2022年6月15日 09:14
      下一篇 2022年6月15日 09:14

      相關(guān)推薦

      • 分手40年之后,葉倩文再遇良人家庭幸福,費翔告別歌壇一生未娶

        5月1日老牌“歌壇天后”葉倩文, 在芒果臺綜藝《聲生不息》最新一期中, 合作李玟和周筆暢兩位實力唱將, 帶來歌曲《我要你的愛》。 舞臺上葉倩文動感唱跳,摩登感十足, 完全看不出是個…

        2022年5月11日
      • 手機電池越做越大,續(xù)航卻沒怎么提升,電量都去哪了?

        相信有很多小伙伴都會好奇,現(xiàn)在的手機電池越做越大,從當(dāng)初的兩三千毫安到如今的 6000mAh,續(xù)航卻沒怎么變化,電量都去哪了呢? 今天我們就來簡單聊一聊,其實主要是以下這幾個原因?!?/p>

        2022年8月19日
      • 蘋果官網(wǎng)樣式調(diào)整 結(jié)賬時產(chǎn)品圖片“巨大化”

        你購物時,是否會在意網(wǎng)站結(jié)賬界面的設(shè)計呢?今天,蘋果對官網(wǎng)的樣式進行了調(diào)整,主要圍繞商品的結(jié)算頁面進行了調(diào)整。修改前,蘋果官網(wǎng)的結(jié)賬頁面采用左右分欄式設(shè)計,左側(cè)為手機外觀,右側(cè)則是…

        2022年8月2日
      • 被實錘了?汪小菲張穎穎甜蜜出游被拍,兩人有說有笑十分開心

        汪小菲大S離婚有段時間了,但是關(guān)于二人的討論卻沒有停止過,因為他們真的是自帶焦點,就比如大S離婚閃嫁具俊曄就讓人很意外 本以為她會有一段時間的感情空窗期,但沒想到她卻做到了無縫銜接…

        2022年7月14日
      • 詳解美國人工智能四大獨角獸公司

        來源 :零壹財經(jīng) 2022年5月9日,《福布斯》雜志發(fā)布了美國人工智能50強公司。人工智能是這個世紀(jì)最值得關(guān)注的技術(shù)之一,目前來看,美國在人工智能領(lǐng)域方面領(lǐng)先全球。 那么,全球人工…

        2022年6月13日
      • 3種連接方式 鍵帽軸體可以定制 Lofree洛斐小翹機械鍵盤個性又實用

        機械鍵盤已經(jīng)是數(shù)碼發(fā)燒友的標(biāo)配,但可玩性比較高的產(chǎn)品幾乎沒有。前段時間,朋友送了一個Lofree洛斐小翹機械鍵盤,鍵帽和軸體都可以定制,可玩性很高。 可以高度定制,這可以滿足很多用…

        2022年6月14日
      • Reno8系列首銷引爆市場 助力OPPO排名第一

        據(jù)華爾街見聞消息,2022年第23周(5月30日-6月5日),OPPO出貨量以17.8%的市占率排名國內(nèi)智能手機市場第一,這其中于6月1日首銷的OPPO Reno8系列明顯起到了重…

        2022年6月15日
      • 拼多多邀請一個新人直接提現(xiàn)(拼多多邀請新用戶直接提現(xiàn)是真的嗎)

        近幾年來伴隨著移動互聯(lián)網(wǎng)技術(shù)的不斷發(fā)展,各大電商平臺也同樣發(fā)展的如火如荼。然而很多人都不知道的是,在這一行業(yè)剛剛發(fā)展起來的時候,整個電商領(lǐng)域幾乎都是由淘寶壟斷的。京東和拼多多都是后…

        2022年10月26日
      • 李大霄:多方部隊突然發(fā)動反攻的六個理由

        英大證券李大霄表示,近段時間空頭肆虐,大有黑云壓城城欲摧之勢,A股亦借勢調(diào)整,從3424點調(diào)整到3155點,這是調(diào)整的時間和空間50%的技術(shù)位置。在3155點堅守了三天之后,在20…

        2022年8月6日
      • “句芒”探碳看點多(美麗中國)

        來源:【人民網(wǎng)】 8月4日11時08分,“句芒號”在太原衛(wèi)星發(fā)射中心成功發(fā)射。 鄭 斌攝(新華社發(fā)) 核心閱讀 近日,我國首顆陸地生態(tài)系統(tǒng)碳監(jiān)測衛(wèi)星“句芒號”發(fā)射成功?!熬涿⑻枴迸洹?/p>

        2022年8月17日

      聯(lián)系我們

      聯(lián)系郵箱:admin#wlmqw.com
      工作時間:周一至周五,10:30-18:30,節(jié)假日休息