 與 int(10) 的區(qū)別:顯示寬度背后的真相與版本演進(jìn))
先問個(gè)問題建表的時(shí)候看到int(10)你的第一反應(yīng)是什么我猜不少人和我一樣一開始以為它和varchar(10)類似表示這個(gè)字段最多只能存 10 個(gè)字符所以int(1)就只能存一位數(shù)字。這個(gè)理解錯(cuò)得相當(dāng)離譜但流傳又特別廣。做 MySQL 面試題收集久了你會(huì)發(fā)現(xiàn)int(1)和int(10)的區(qū)別幾乎是必問基礎(chǔ)題也是最能看出一個(gè)人到底有沒有真正落地寫過表的分水嶺。今天不繞彎子直接把結(jié)論放在最前面在 MySQL 里int(1)和int(10)在存儲(chǔ)、取值范圍、索引、排序等任何底層行為上完全一致它們都是同一個(gè)int類型都占 4 個(gè)字節(jié)。括號(hào)里的數(shù)字既不是長(zhǎng)度限制也不是位數(shù)限制它只是 MySQL 里的一個(gè)“顯示寬度”概念。這篇文章主要面向剛接觸 MySQL 的同學(xué)也能幫自以為懂的老手梳理一下版本演進(jìn)帶來的變化尤其是 MySQL 8.0.17 之后官方對(duì)顯示寬度的處理方式很多人還停在舊版本的認(rèn)知里。1. 先搞清楚int(1) 和 int(10) 到底在比什么1.1 括號(hào)里的 M 是顯示寬度不是存儲(chǔ)長(zhǎng)度先說一個(gè)最容易混淆的點(diǎn)。varchar(10)里的 10 是字符長(zhǎng)度限制這個(gè)字符串最多存 10 個(gè)字符你寫第 11 個(gè)字符就會(huì)報(bào)錯(cuò)。但int(M)里的 M 全稱叫 display width翻譯過來是“顯示寬度”它不是存儲(chǔ)長(zhǎng)度更不是取值范圍。int 類型在 MySQL 內(nèi)部是固定長(zhǎng)度永遠(yuǎn)是 4 個(gè)字節(jié)你寫不寫括號(hào)、括號(hào)里寫 1 還是寫 10甚至寫 255磁盤上占的空間都一樣??梢赃@么理解int像是一個(gè)固定大小的容器容量從一開始就焊死了4 字節(jié)能裝多少就裝多少。括號(hào)里的數(shù)字只是給這個(gè)容器外面貼的一張標(biāo)簽告訴客戶端“如果要用零填充顯示請(qǐng)補(bǔ)到幾位”。這張標(biāo)簽改變不了容器本身的大小就像你在一個(gè) 4 升的桶上貼了“1L”或者“10L”的貼紙桶還是那個(gè)桶能裝的水還是 4 升區(qū)別僅僅是有人看貼紙時(shí)可能會(huì)誤以為桶的容量變了。還有一點(diǎn)值得記住顯示寬度在 MySQL 5.7 及更早版本里是有上限的最大是 255。你寫int(256)在舊版本里會(huì)直接報(bào)錯(cuò)提示 display width out of range。但在 MySQL 8.0.19 之后這個(gè)限制基本失去意義因?yàn)轱@示寬度已經(jīng)被官方廢棄了具體廢棄邏輯放到后面第 4 節(jié)細(xì)說。1.2 存儲(chǔ)和取值范圍兩個(gè)完全一樣這一節(jié)是很多人踩坑的根源。int(1)和int(10)既然都是 int那取值范圍就完全由 int 這個(gè)類型決定。有符號(hào)情況下int 的取值范圍是-2147483648到2147483647無符號(hào)情況下取值范圍是0到4294967295。換句話說int(1)完全可以存儲(chǔ)2147483647這個(gè)十位數(shù)它在存儲(chǔ)層面沒有任何限制。有些項(xiàng)目里字段寫成int(1)業(yè)務(wù)方就認(rèn)為“這個(gè)字段只能存 0 到 9”結(jié)果某個(gè)金額超過 9 就報(bào)錯(cuò)最后排查半天發(fā)現(xiàn)不是數(shù)據(jù)問題而是當(dāng)初建表的人被這個(gè)括號(hào)騙了。這種問題在真實(shí)項(xiàng)目里出現(xiàn)過很多次尤其是從網(wǎng)上復(fù)制建表語(yǔ)句時(shí)特別容易留下這種歷史包袱。再補(bǔ)充一點(diǎn)性能層面的結(jié)論int(1)和int(10)的索引大小、索引比較代價(jià)、排序代價(jià)、JOIN 代價(jià)完全一樣因?yàn)樗鼈儽举|(zhì)上就是同一個(gè)數(shù)據(jù)類型。你給int(1)建索引和給int(10)建索引沒有任何區(qū)別不要覺得位數(shù)寫小一點(diǎn)索引就更快這是不存在的。1.3 這個(gè)錯(cuò)覺是怎么流傳開來的既然顯示寬度這么容易誤導(dǎo)人為什么還會(huì)被大量寫進(jìn)建表語(yǔ)句我總結(jié)下來主要有三個(gè)來源。最直接的原因是把varchar的習(xí)慣遷移到了int上。很多人學(xué) MySQL 時(shí)先學(xué)的字符串類型知道括號(hào)里的數(shù)字是最大長(zhǎng)度于是看到別人的表里有int(10)想當(dāng)然地以為這也是長(zhǎng)度限制。網(wǎng)上大量“從零開始學(xué) MySQL”的教程和問答里也充斥著類似說法一旦流傳開新手很難辨別。第二個(gè)來源是圖形化工具。Navicat、MySQL Workbench 這些工具在導(dǎo)出建表語(yǔ)句時(shí)經(jīng)常給你生成int(10)或者int(11)這樣的寫法。尤其是int(11)這個(gè)數(shù)字其實(shí)是有來歷的int 有符號(hào)類型能存儲(chǔ)最小值-2147483648算上負(fù)號(hào)一共 11 個(gè)字符所以顯示寬度取 11 就是為了完整顯示這個(gè)最小值。int(10) unsigned也類似因?yàn)闊o符號(hào) int 的最大值4294967295剛好是 10 位。工具自動(dòng)生成不代表這就是業(yè)務(wù)設(shè)計(jì)建議它只是照著元數(shù)據(jù)里的顯示寬度原樣導(dǎo)出而已。第三個(gè)來源就是歷史習(xí)慣。早期 MySQL 版本里官方文檔和不少經(jīng)典書籍里的示例表都寫著int(11)于是一代代開發(fā)者照抄。抄的人不知道為什么要寫 11但也不敢隨便改最后這種寫法就成了“行業(yè)潛規(guī)則”。你問他們?yōu)槭裁磳慽nt(10)最常見的回答就是“看別人都這么寫”。2. int(M) 唯一顯眼的作用zerofill 補(bǔ)零2.1 不加 zerofillM 基本就是個(gè)擺設(shè)如果在建表語(yǔ)句里只寫int(10)不給它加任何額外屬性那這個(gè) 10 你在查詢結(jié)果里根本感覺不到。比如你插入一個(gè)數(shù)字1查詢出來就是1它不會(huì)自動(dòng)顯示成0000000001。所以可以說在不使用 zerofill 的情況下int(1)和int(10)從 SQL 執(zhí)行結(jié)果上完全無法區(qū)分。真正讓 M 起作用的是zerofill屬性中文叫“零填充”。當(dāng)你把字段定義成int(10) zerofill時(shí)如果存儲(chǔ)的數(shù)值位數(shù)不足 10 位MySQL 在查詢結(jié)果里會(huì)自動(dòng)在左邊補(bǔ) 0補(bǔ)到 10 位為止。比如插入1查詢出來是0000000001插入999查詢出來是0000000999。這里有個(gè)容易忽略的細(xì)節(jié)如果你定義的是int(1) zerofill那插入1顯示還是1因?yàn)?1 本身就已經(jīng)達(dá)到顯示寬度了。寬度不足時(shí)不會(huì)補(bǔ)零寬度足夠時(shí)需要補(bǔ)零這個(gè)邏輯和字符串填充非常像。因?yàn)閕nt(1)的顯示寬度只有 1所以它幾乎不會(huì)觸發(fā)補(bǔ)零行為除非你存負(fù)數(shù)——但下面馬上要說zerofill 字段其實(shí)存不了負(fù)數(shù)。2.2 用了 zerofill 后會(huì)自動(dòng)變成無符號(hào)這是 zerofill 里第二個(gè)容易踩的坑。在 MySQL 里一旦給整數(shù)列加上 zerofill 屬性該列會(huì)自動(dòng)附帶 unsigned 屬性也就是變成無符號(hào)整數(shù)。官方文檔里明確寫了“ZEROFILL implies UNSIGNED”這不是可選行為而是強(qiáng)制的。什么意思呢如果你建了money int(10) zerofill那這個(gè)字段的取值范圍就不再是-2147483648到2147483647而是0到4294967295。你往里面插負(fù)數(shù)會(huì)直接報(bào) Out of range數(shù)據(jù)根本寫不進(jìn)去。很多人在做固定位數(shù)的編號(hào)、訂單號(hào)時(shí)指望用 zerofill 補(bǔ)零結(jié)果項(xiàng)目里又要存負(fù)數(shù)兩邊需求一沖突才發(fā)現(xiàn)這個(gè)隱含約束。從 MySQL 8.0.17 開始zerofill 屬性本身也已經(jīng)被官方標(biāo)記為廢棄和顯示寬度一起進(jìn)入淘汰流程。所以現(xiàn)在新項(xiàng)目里基本沒有任何理由再去用 zerofill 做業(yè)務(wù)邏輯。它看起來像是一個(gè)很方便的展示工具但實(shí)際會(huì)引入 unsigned 語(yǔ)義、版本兼容問題和跨庫(kù)遷移風(fēng)險(xiǎn)性價(jià)比很低。2.3 生產(chǎn)環(huán)境別把顯示寬度當(dāng)業(yè)務(wù)約束我見過一些項(xiàng)目把int(4)當(dāng)成“這里最多只能填四位數(shù)”來用這是非常危險(xiǎn)的做法。因?yàn)轱@示寬度根本不產(chǎn)生任何輸入限制你往int(4)里插入123456完全沒問題它照樣存進(jìn)去查詢出來也照樣是123456。真正要限制數(shù)字大小要么用業(yè)務(wù)層校驗(yàn)要么用更小范圍的類型比如smallint而不是指望括號(hào)里的數(shù)字。同理固定位數(shù)的業(yè)務(wù)編號(hào)、訂單號(hào)這類需求也不建議用int(M) zerofill去實(shí)現(xiàn)。原因有幾個(gè)第一補(bǔ)零只是查詢顯示效果導(dǎo)出的數(shù)據(jù)、通過客戶端查看的數(shù)據(jù)可能不帶補(bǔ)零數(shù)據(jù)一致性不直觀第二zerofill 隱含無符號(hào)業(yè)務(wù)字段一旦需要負(fù)數(shù)就廢了第三換數(shù)據(jù)庫(kù)或者換版本后行為可能不一致尤其 MySQL 8.0.19 之后顯示寬度基本被忽略你的int(10) zerofill在新版本里可能不再補(bǔ)零至少 DDL 層面已經(jīng)看不到那個(gè) 10 了。更穩(wěn)妥的方案是用 varchar 存儲(chǔ)固定位數(shù)的編號(hào)在業(yè)務(wù)代碼里用LPAD或者字符串格式化統(tǒng)一補(bǔ)零如果確實(shí)是純數(shù)字且需要參與數(shù)值運(yùn)算那就用普通的 int 或 bigint展示時(shí)再格式化。數(shù)據(jù)庫(kù)層只負(fù)責(zé)存數(shù)據(jù)和保證數(shù)據(jù)完整性展示格式的活應(yīng)該交給應(yīng)用層。3. 為什么不看 int(1) 還是 int(10)要看 int 本身3.1 4 字節(jié)的 int 到底能存多少回到根子上MySQL 的整數(shù)類型是按字節(jié)數(shù)劃分的不是按括號(hào)里的數(shù)字劃分。TINYINT占 1 字節(jié)SMALLINT占 2 字節(jié)MEDIUMINT占 3 字節(jié)INT占 4 字節(jié)BIGINT占 8 字節(jié)。int(1)、int(10)、int都落在 INT 這一檔所以它們的容量天花板完全一致。字節(jié)數(shù)和位數(shù)之間的關(guān)系其實(shí)挺簡(jiǎn)單一個(gè)字節(jié) 8 位intonation 4 個(gè)字節(jié)就是 32 位。有符號(hào)時(shí)最高位做符號(hào)位能表示的最大值就是2^31 - 1也就是 2147483647最小值是-2^31也就是 -2147483648。無符號(hào)時(shí)所有位都用來表示數(shù)值最大值就是2^32 - 1即 4294967295。只要理解了這一層就不會(huì)再被括號(hào)里的數(shù)字帶偏。這里可以順手記住一個(gè)常用判斷int有符號(hào)最大值是十位數(shù) 2147483647所以如果你的業(yè)務(wù)主鍵、自增 ID 有可能超過這個(gè)數(shù)比如幾億用戶表、日志流水表直接上bigint不要心存僥幸。顯示寬度救不了你類型選錯(cuò)才是真正的大問題。3.2 int(1) 和 tinyint(1) 是兩碼事很多人還會(huì)把int(1)和tinyint(1)搞混因?yàn)樗鼈兌紟в?1)看起來好像差不多。實(shí)際上差別非常大int(1)是 4 字節(jié)的 int 類型取值范圍是完整的 int 范圍tinyint(1)是 1 字節(jié)的 tinyint 類型有符號(hào)范圍只有-128到127。它們的共同點(diǎn)是顯示寬度都寫著 1但底層數(shù)據(jù)類型完全不同。tinyint(1) 在 MySQL 生態(tài)里還有一個(gè)特殊身份它經(jīng)常被當(dāng)作布爾類型使用。MySQL 里的BOOL和BOOLEAN其實(shí)都不是獨(dú)立的類型而是TINYINT(1)的別名。你建表寫flag BOOLEAN執(zhí)行SHOW CREATE TABLE看到的往往就是tinyint(1)。很多編程語(yǔ)言的驅(qū)動(dòng)、ORM 框架在讀取元數(shù)據(jù)時(shí)也約定俗成地會(huì)把tinyint(1)映射成布爾值。所以這里有一條實(shí)用建議想存布爾狀態(tài)用tinyint(1)而不是int(1)。如果你用了int(1)存 0/1功能上沒問題但白白浪費(fèi) 3 個(gè)字節(jié)而且一些 ORM 不會(huì)把它識(shí)別成布爾類型代碼里還要額外做轉(zhuǎn)換屬于給自己找麻煩。等到 MySQL 8.0.19 之后整數(shù)顯示寬度被廢棄唯獨(dú)tinyint(1)作為特殊情況被保留下來也正是因?yàn)?MySQL 生態(tài)里有大量代碼依賴tinyint(1)的布爾語(yǔ)義。3.3 M 不影響索引、排序和比較既然顯示寬度只是展示屬性那它對(duì)數(shù)據(jù)庫(kù)行為的影響面其實(shí)非常小。索引自然不用說了int(1)和int(10)建出來的索引結(jié)構(gòu)完全一樣B 樹的比較邏輯完全按 int 數(shù)值來不會(huì)因?yàn)轱@示寬度不同而走不同的路徑。排序也是同一個(gè)道理。很多人問“mysql 排序”時(shí)遇到數(shù)字排序亂掉的問題通常是把數(shù)字存成了 varchar導(dǎo)致排序按字符串字典序走出現(xiàn) 1、10、2 這種結(jié)果。但如果字段是正兒八經(jīng)的 int 類型無論你寫int(1)還是int(10)排序都嚴(yán)格按數(shù)值大小來絕不會(huì)出現(xiàn)“1 排在 10 前面”這種字符串錯(cuò)覺。WHERE 條件也一樣。WHERE id_a 1和WHERE id_b 1執(zhí)行計(jì)劃、查詢性能沒有差異。退一步說如果你真想讓數(shù)據(jù)庫(kù)層面的整數(shù)帶上前導(dǎo)零去排序、去展示那也得靠 zerofill 或者字符串類型普通的int(1)幫不上任何忙。4. MySQL 版本演進(jìn)8.0.17 之后這個(gè)問題會(huì)被歷史淘汰4.1 官方為什么要廢棄顯示寬度看到這里你應(yīng)該也感覺到了int 顯示寬度這個(gè)設(shè)計(jì)相當(dāng)別扭。它既不能限制存儲(chǔ)又不參與運(yùn)算只在極少數(shù)配合 zerofill 的場(chǎng)景下影響查詢結(jié)果卻成功誤導(dǎo)了一大批開發(fā)者。MySQL 官方顯然也意識(shí)到了這個(gè)問題所以在 8.0.17 版本中正式將整數(shù)顯示寬度標(biāo)記為廢棄并在后續(xù)版本中逐步移除了對(duì)它的支持。官方廢棄的理由其實(shí)很直白顯示寬度本質(zhì)上是客戶端展示層的東西不該出現(xiàn)在數(shù)據(jù)庫(kù)字段定義里。它給開發(fā)者造成了一種虛假的安全感讓人覺得括號(hào)里的數(shù)字能控制輸入長(zhǎng)度實(shí)際上根本沒有約束力。再加上 zerofill 隱含 unsigned 這種隱藏語(yǔ)義進(jìn)一步增加了使用成本整體設(shè)計(jì)得不償失廢棄只是時(shí)間問題。4.2 升級(jí)到 8.0.19 后建表行為的變化從 MySQL 8.0.19 開始整數(shù)類型的顯示寬度正式不再支持除了tinyint(1)這個(gè)布爾特例被保留其他int(1)、int(10)、int(11)之類的寫法在 DDL 解析后都會(huì)被忽略。你在建表語(yǔ)句里仍然可以寫int(10)而不報(bào)錯(cuò)但執(zhí)行完再SHOW CREATE TABLE看到的通常就只是int不再有括號(hào)里的數(shù)字。這個(gè)變化對(duì)存量數(shù)據(jù)沒有任何影響因?yàn)榈讓哟鎯?chǔ)的始終是 4 字節(jié) int顯示寬度從來不會(huì)改變數(shù)據(jù)。真正值得注意的是元數(shù)據(jù)層面的差異如果你還在用 MySQL 5.7腳本里SHOW CREATE TABLE會(huì)原樣輸出int(10)如果升級(jí)到 8.0.19同樣一張表導(dǎo)出的 DDL 可能就變成int了。對(duì)于那些靠字符串比對(duì) DDL 的巡檢工具、表結(jié)構(gòu) diff 工具、數(shù)據(jù)遷移平臺(tái)來說這種輸出差異需要提前適配。4.3 老 DDL 和工具生成的腳本怎么辦如果你維護(hù)的是老項(xiàng)目表結(jié)構(gòu)里到處都是int(10)、int(11)不要慌這些字段不需要重建表數(shù)據(jù)也不會(huì)出問題。顯示寬度被忽略之后最直接的影響只是元數(shù)據(jù)展示變了應(yīng)用代碼讀到的數(shù)據(jù)庫(kù)類型仍然是 int索引、主鍵、外鍵邏輯一概不變。真正需要?jiǎng)邮謾z查的是自動(dòng)化工具鏈。比如你用 pt-online-schema-change 做在線 DDL 變更用 gh-ost 做無鎖表結(jié)構(gòu)遷移或者用自研的比對(duì)系統(tǒng)去比對(duì)測(cè)試庫(kù)和生產(chǎn)庫(kù)結(jié)構(gòu)當(dāng)兩端 MySQL 版本不一致時(shí)可能出現(xiàn)“明明邏輯相同但字段定義字符串不同”的判定結(jié)果。建議在臨時(shí)環(huán)境里做一次 5.7 到 8.0 的升級(jí)演練把建表腳本重新導(dǎo)出統(tǒng)一改造成不帶顯示寬度的寫法讓工具鏈盡早適應(yīng)新格式。關(guān)于新項(xiàng)目的建表規(guī)范我的態(tài)度很明確直接寫int不要帶括號(hào)。沒有 zerofill 需求時(shí)int(1)和int(10)都是畫蛇添足有顯示需求時(shí)也該用應(yīng)用層格式化而不是靠數(shù)據(jù)庫(kù)的廢棄特性。保持 DDL 干凈比保護(hù)一個(gè)莫名其妙的舊習(xí)慣重要得多。5. 自己動(dòng)手驗(yàn)證一遍5 分鐘消除所有疑慮5.1 建表插入看真實(shí)存儲(chǔ)效果說再多不如跑一遍。下面這組 SQL 在 MySQL 5.7 或 8.0.18 及更早版本上執(zhí)行能完整看到顯示寬度和 zerofill 的效果如果你用的是 8.0.19也可以執(zhí)行只是最后一節(jié)SHOW CREATE TABLE的輸出里可能不再保留括號(hào)里的數(shù)字。CREATE TABLE int_demo ( id_a INT(1), id_b INT(10), id_c INT(1) ZEROFILL, id_d INT(10) ZEROFILL ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; INSERT INTO int_demo VALUES (1, 1, 1, 1); INSERT INTO int_demo VALUES (999, 999, 999, 999); INSERT INTO int_demo VALUES (2147483647, 2147483647, 2147483647, 2147483647);注意第三行插入的數(shù)字是 int 有符號(hào)最大值 2147483647四個(gè)列都能正常接收。如果你插入的是一億以上的數(shù)據(jù)id_c和id_d因?yàn)?zerofill 隱含 unsigned也能接收更大的值但id_a和id_b到了 4294967295 就會(huì)報(bào) out of range這個(gè)對(duì)比很能說明 unsigned 帶來的邊界差異。5.2 查詢結(jié)果對(duì)比一下執(zhí)行下面這條查詢SELECT id_a, id_b, id_c, id_d FROM int_demo;在支持顯示寬度的版本里預(yù)期結(jié)果是這樣的列名類型定義插入 1 顯示插入 999 顯示插入 2147483647 顯示id_aint(1)19992147483647id_bint(10)19992147483647id_cint(1) zerofill19992147483647id_dint(10) zerofill000000000100000009992147483647可以看到id_a雖然是int(1)但它照樣顯示 999 和 2147483647完全沒有長(zhǎng)度限制。id_d因?yàn)閹nt(10) zerofill在數(shù)值不足 10 位時(shí)自動(dòng)補(bǔ)零插入 1 顯示為0000000001插入 999 顯示為0000000999。而當(dāng)數(shù)值超過顯示寬度時(shí)比如 2147483647 本身是 10 位已經(jīng)達(dá)到int(10)的顯示寬度所以不再補(bǔ)零。這里還有個(gè)細(xì)節(jié)值得順手驗(yàn)證id_c是int(1) zerofill但插入 999 后顯示仍然是999MySQL 不會(huì)因?yàn)轱@示寬度不足就截?cái)鄶?shù)據(jù)。它只會(huì)做補(bǔ)零從來不做截?cái)噙@一點(diǎn)也和字符串類型的行為完全不同。5.3 補(bǔ)零只是顯示存儲(chǔ)和運(yùn)算仍是數(shù)字再用兩條查詢驗(yàn)證 zerofill 的“虛”的一面。第一條用數(shù)字條件匹配SELECT id_a, id_b, id_d FROM int_demo WHERE id_d 1;如果你插入了第一行(1, 1, 1, 1)這條查詢能正常命中說明雖然id_d查詢顯示為0000000001但它在數(shù)據(jù)庫(kù)里存的仍然是數(shù)值 1比較時(shí)也按數(shù)值 1 處理不會(huì)因?yàn)轱@示寬度變成字符串 “0000000001”。第二條做一次算術(shù)運(yùn)算SELECT id_d, id_d 0 AS numeric_val FROM int_demo WHERE id_a 1;id_d 0的結(jié)果是 1而不是 0000000001。這從底層證明了補(bǔ)零只是查詢結(jié)果的展示效果存儲(chǔ)、計(jì)算、比較全部走 int 數(shù)值邏輯??赐赀@幾條 SQLint(1)和int(10)的區(qū)別應(yīng)該就不會(huì)再有任何疑問了。6. 實(shí)戰(zhàn)常見問題與面試速查6.1 高頻問題排查清單問題正確答案容易踩的坑int(1) 是不是最多只能存 9不是int(1) 仍是完整 int 范圍能存到 21 億以上把顯示寬度當(dāng)成輸入長(zhǎng)度限制int(10) 是不是最多只能存 10 位不是有符號(hào) int 上限 2147483647 就是 10 位但這是類型決定不是寬度決定以為 10 是位數(shù)上限int(10) 和 int(11) 誰(shuí)存得更多一樣多都是 int存儲(chǔ)范圍完全一致以為 11 比 10 多一位容量寫 int(255) 可以嗎舊版本顯示寬度上限是 255可以但不代表能存 255 位以為 255 是 255 位數(shù)int(10) unsigned 是什么意思無符號(hào) int范圍 0 到 429496729510 是顯示寬度忽略 unsigned 帶來的范圍變化用了 zerofill 能存負(fù)數(shù)嗎不能zerofill 隱含 unsigned插入負(fù)數(shù)直接報(bào)錯(cuò)拿 zerofill 做編號(hào)時(shí)突然存不進(jìn)負(fù)數(shù)這張表基本覆蓋了我在社區(qū)里看到的高頻誤解。如果踩過其中任何一個(gè)把第 5 節(jié)的實(shí)驗(yàn) SQL 跑一遍比看任何文檔都管用。6.2 面試這樣回答才不翻車面試?yán)锉粏柕絠nt(1)和int(10)的區(qū)別建議按三個(gè)層次回答既展示基礎(chǔ)扎實(shí)又體現(xiàn)對(duì)版本演進(jìn)的關(guān)注。第一層直接說結(jié)論存儲(chǔ)層面沒區(qū)別都是 4 字節(jié) int取值范圍完全一致索引、排序、性能也沒有任何差異。第二層解釋括號(hào)里的數(shù)字是顯示寬度 display width主要配合 zerofill 使用不加 zerofill 時(shí)沒有任何實(shí)際效果。第三層補(bǔ)充版本演進(jìn)從 MySQL 8.0.17 開始顯示寬度被廢棄8.0.19 之后整數(shù)類型不再支持顯示寬度僅tinyint(1)因?yàn)椴紶栒Z(yǔ)義被保留。如果面試官追問為什么老建表語(yǔ)句里老看到int(11)就把我前面說的原因拋出來int 有符號(hào)最小值是 -2147483648算上負(fù)號(hào)共 11 個(gè)字符所以顯示寬度取 11 是為了完整顯示最小值無符號(hào) int 最大值是 4294967295共 10 位所以很多工具導(dǎo)出int(10) unsigned。能說到這個(gè)層面基本就是高分答案了。6.3 我在實(shí)際項(xiàng)目里的體會(huì)最后說點(diǎn)實(shí)在的。我最早寫表結(jié)構(gòu)時(shí)同樣以為int(1)只能存一位數(shù)后來在一場(chǎng)評(píng)審會(huì)上被 DBA 追問為什么總額字段要定義成int(1)當(dāng)場(chǎng)翻官方文檔才徹底搞明白。那次經(jīng)歷讓我養(yǎng)成了一個(gè)習(xí)慣所有 int 列建表時(shí)不寫括號(hào)里的數(shù)字讓類型保持它本來的樣子需要 0/1 布爾就用 tinyint(1)需要更大范圍就上 bigint展示格式一律交給應(yīng)用層。這種習(xí)慣在 MySQL 8.0.19 之后尤其舒服因?yàn)楣俜揭呀?jīng)把顯示寬度移除寫不寫括號(hào)最終都會(huì)被忽略。與其守著舊習(xí)慣繼續(xù)寫int(10)不如現(xiàn)在就開始簡(jiǎn)化 DDL。再遇到同事問“int(1) 和 int(10) 哪個(gè)大”把這篇里的 SQL 丟給他跑一遍他可能比你先頓悟。