Int(4)和Int(11) 你選的是哪個(gè)?
緣起
大家平時(shí)在進(jìn)行數(shù)據(jù)庫(kù)設(shè)計(jì)的時(shí)候,如果遇到需要存儲(chǔ)整數(shù)類型的數(shù)據(jù)的時(shí)候,通常會(huì)優(yōu)先使用Int這個(gè)整數(shù)類型,在處理20億級(jí)別的正負(fù)數(shù)值存儲(chǔ)上,Int類型是完全能夠滿足日常需求的了。
但是在進(jìn)行數(shù)據(jù)庫(kù)建表語句書寫的時(shí)候,大家經(jīng)常會(huì)見到Int類型的后面會(huì)帶上1個(gè)括號(hào),里面跟上1個(gè)數(shù)值,通常要么是4,要么是11。如下:
這 int 括號(hào)里面的數(shù)值,究竟是什么意思呢?有的開發(fā)者認(rèn)為,這個(gè)數(shù)值是用來限制Int類型能夠存儲(chǔ)的數(shù)字的長(zhǎng)度的( 類似char、varchar括號(hào)數(shù)值 );有的開發(fā)者則認(rèn)為,在存儲(chǔ)相同數(shù)字的情況下,Int(4)會(huì)比Int(11)在存儲(chǔ)上節(jié)省更多的存儲(chǔ)空間。
那么實(shí)際情況究竟是怎樣的呢?在實(shí)際的數(shù)據(jù)庫(kù)設(shè)計(jì)中,究竟應(yīng)該使用Int(4)還是Int(11)呢?又或者是應(yīng)該什么都不寫,只用默認(rèn)的Int呢?
讓我們開啟今天的MySQL數(shù)據(jù)庫(kù)之Int類型之旅。^_^
存儲(chǔ)比較
為了方便測(cè)試Int(4)、Int(11)、以及默認(rèn)的Int,在存儲(chǔ)上是否存在差別,我們分別創(chuàng)建t_int_four、t_int_eleven、t_int_default表,如下:
接下來,我們向t_int_four表的my_int_four字段,插入Int( 有符號(hào) )類型的最大值2147483647,如下:
如上圖,我們看到m_int_four字段的Int(4)類型,并沒有影響到Int類型最大值2147483647的插入。可見這個(gè)Int括號(hào)中的數(shù)值4,并不是對(duì)數(shù)字長(zhǎng)度的存儲(chǔ)進(jìn)行限制的,也就是說,只要不超過Int( 有符號(hào) )類型的最小值和最大值的范圍,都是可以正確存儲(chǔ)的。
接下來我們向t_int_eleven表的my_int_eleven字段,插入Int類型的最大值2147483647。如下:
如上圖,我們看到,my_int_eleven字段的Int(11),也成功存儲(chǔ)了Int類型的最大值2147483647。
接下來我們向t_int_default表的my_int_default字段,插入Int類型的最大值。如下:
如上圖,my_int_default字段的Int類型,也成功存儲(chǔ)了Int類型的最大值。這也就進(jìn)一步證明了,Int類型括號(hào)中的數(shù)值,對(duì)該列字段的數(shù)值的存儲(chǔ)長(zhǎng)度是沒有任何影響的,只要不超出Int類型的數(shù)值范圍,都是可以被正確存儲(chǔ)的。
這里我們發(fā)現(xiàn)Int類型的最大值2147483647,是一個(gè)10位長(zhǎng)度的數(shù)字,那么my_int_eleven字段的Int(11),能否突破Int類型的最大值,存儲(chǔ)11位長(zhǎng)度的數(shù)值呢?
我們存入一個(gè)11位的數(shù)字,如下:
如上圖,這里我們發(fā)現(xiàn),即便設(shè)置了Int(11)的列字段,依然無法突破Int類型的數(shù)值范圍存儲(chǔ)限制,最終還是只允許存儲(chǔ)Int( 有符號(hào) )類型的有效數(shù)值范圍。
那么Int(4)、Int(11)、以及默認(rèn)的Int,在存儲(chǔ)空間的占用上是否存在差別呢?是否相同位數(shù)長(zhǎng)度的數(shù)值,Int(4)就比Int(11)節(jié)省更多的物理存儲(chǔ)空間呢?
接下來,我們打開磁盤上的表t_int_four、t_int_eleven、t_int_default這3個(gè)表的表空間文件( 后綴名是.ibd ),打開進(jìn)行對(duì)比,如下:
從上圖的元數(shù)據(jù)中,我們看到不管是t_int_four的Int(4),還是t_int_eleven的Int(11),甚至是t_int_default的Int,在存儲(chǔ)空間占用上,都是用了4個(gè)字節(jié)的空間大小,這里的FF FF FF FF,就是我們所存儲(chǔ)的Int類型的最大值2147483647,如下:
由于我們的Int類型是有符號(hào)的,也就是能存儲(chǔ)負(fù)數(shù)。所以這里的4294967295需要除以2,得到有符號(hào)的正數(shù)2147483647,就是Int( 有符號(hào) )類型的最大值了。
關(guān)于有符號(hào)整數(shù)的存儲(chǔ)及計(jì)算方法,大家可以在網(wǎng)上自行查詢腦補(bǔ),這里就不再陳述了。
ZEROFILL
經(jīng)過上面的示例,我們已經(jīng)知道Int類型括號(hào)中的數(shù)值,并不是控制錄入數(shù)據(jù)的數(shù)值位數(shù)長(zhǎng)度的,那么它究竟是用來干什么的呢?
在《MySQL中文參考手冊(cè)》中,數(shù)值類型的列字段,都有一個(gè)叫做ZEROFILL的可選屬性,如下:
按照文檔中的介紹,如果一個(gè)數(shù)值類型的列字段,加上了ZEROFILL的屬性后,該列類型會(huì)自動(dòng)變?yōu)閁nsigned( 無符號(hào) )類型,并具備自動(dòng)補(bǔ)0的功能。
那么究竟是什么樣的效果呢?下面我們看一個(gè)示例。
如上圖,在t_int_zerofill表中,我們分別創(chuàng)建了表示Int(4)、Int(11)、Int的3個(gè)字段:my_int_four、my_int_eleven、my_int_default。
我們?cè)诓迦肓?條每個(gè)字段值為數(shù)字1的數(shù)據(jù)后,發(fā)現(xiàn)查詢出來的結(jié)果表中,自動(dòng)在每個(gè)Int類型的字段列上,補(bǔ)了數(shù)字0。使得每一個(gè)數(shù)字列中的數(shù)值長(zhǎng)度,正好等于該列字段Int括號(hào)中數(shù)值的長(zhǎng)度。如下:
上面表格中,我們發(fā)現(xiàn),如果Int類型的列字段中,存儲(chǔ)的數(shù)值的位長(zhǎng)度,小于Int括號(hào)中的數(shù)值( 后面統(tǒng)一叫做ZEROFILL長(zhǎng)度 ),MySQL在查詢顯示的時(shí)候,就會(huì)自動(dòng)在該列的存儲(chǔ)數(shù)值的左邊,進(jìn)行補(bǔ)0。使得整個(gè)顯示值的總長(zhǎng)度,等于Int列類型的ZEROFILL長(zhǎng)度。
如果使用的是Int默認(rèn)類型,則按照Int( 無符號(hào) )類型存儲(chǔ)的最大數(shù)值的位長(zhǎng)度進(jìn)行補(bǔ)0,這里Int( 無符號(hào) )類型的最大值為4294967295,也就是10位。所以my_int_default在顯示數(shù)字1時(shí),補(bǔ)9位0+1位數(shù)字(1),正好是10位。
接下來,我們插入1條各字段數(shù)值為1234的數(shù)據(jù),如下:
如上圖,這里我們看到,在插入1234之后,my_int_four的Int(4),就沒有再進(jìn)行補(bǔ)0了,因?yàn)閿?shù)字1234的位長(zhǎng)度,正好等于my_int_four列字段的ZEROFILL長(zhǎng)度,也就是Int(4)。而其它列my_int_eleven和my_int_default,依然按照各自的ZEROFILL長(zhǎng)度進(jìn)行補(bǔ)0顯示。
混合示例
經(jīng)過上面的示例,我們知道Int類型的ZEROFILL長(zhǎng)度參數(shù)的用法,那么其他的數(shù)值類型,是否也同樣使用ZEROFILL長(zhǎng)度參數(shù)的用法規(guī)則呢?
我們創(chuàng)建t_int_complex_zerofill表,并設(shè)置不同的數(shù)值類型的列字段,如下:
接下來,插入1條測(cè)試數(shù)據(jù),分別為每一個(gè)列字段,設(shè)置該數(shù)值列類型的無符號(hào)最大數(shù)值,如下:
如上圖,各種數(shù)值類型的ZEROFILL長(zhǎng)度參數(shù),依然對(duì)數(shù)值列類型本身的存儲(chǔ)大小,是沒有影響的。
接下來我們插入1條,各列字段數(shù)值為1的測(cè)試數(shù)據(jù),如下:
如上圖,各種數(shù)字類型的ZEROFILL長(zhǎng)度參數(shù)都起到了預(yù)期的補(bǔ)0作用。
總結(jié)
本篇主要針對(duì)MySQL數(shù)據(jù)庫(kù)設(shè)計(jì)中,Int類型的列字段中,括號(hào)中不同補(bǔ)0長(zhǎng)度的數(shù)值設(shè)置,以及其他具備相似特性的數(shù)值列類型,進(jìn)行對(duì)了對(duì)比和分析。
經(jīng)過不同的示例分析,我們知道了數(shù)值列類型的補(bǔ)0長(zhǎng)度的數(shù)值設(shè)置,也就是ZEROFILL的長(zhǎng)度參數(shù)設(shè)置,對(duì)數(shù)值列類型本身的存儲(chǔ)是沒有任何影響的。
在數(shù)值列類型的字段上,如果沒有顯示聲明“ZEROFILL”標(biāo)識(shí)的話,只要存儲(chǔ)的數(shù)值不超過該數(shù)字列類型( 有符號(hào) )的數(shù)值范圍,就都可以正確存儲(chǔ)。也就是說Int(4)和Int(11)在存儲(chǔ)大小上,是沒有任何差別和限制的。
數(shù)值列類型的補(bǔ)0長(zhǎng)度的數(shù)值設(shè)置,只有在該數(shù)值列類型的字段上,顯示聲明“ZEROFILL”標(biāo)識(shí)之后,才會(huì)按照數(shù)值列類型的補(bǔ)0長(zhǎng)度( ZEROFILL長(zhǎng)度參數(shù) ),進(jìn)行補(bǔ)0顯示。
那么為什么在很多MySQL的建表語句中,會(huì)經(jīng)常見到?jīng)]有ZEROFILL標(biāo)識(shí)的Int(4)和Int(11)的寫法呢?
阿K認(rèn)為,這里可能主要有2種方向的考慮。
- Int(11):因?yàn)镮nt( 有符號(hào) )類型的最大數(shù)值為2147483647,位長(zhǎng)度是10。那么在存儲(chǔ)的時(shí)候,就能從括號(hào)中看出來,在進(jìn)行數(shù)據(jù)插入的時(shí)候,就不要輸入11位長(zhǎng)度的數(shù)字,比如:12345678901,就是超出范圍的非法數(shù)據(jù)。用作數(shù)字插入的預(yù)警作用。
- Int(4):因?yàn)镮nt列類型的存儲(chǔ)空間大小為4字節(jié),在設(shè)計(jì)和存儲(chǔ)的時(shí)候,就能夠從括號(hào)中看出來Int列類型的占用空間大小,從而結(jié)合char、varchar等其它列的類型,方便的計(jì)算出來每條數(shù)據(jù)在插入的時(shí)候,所占用存儲(chǔ)空間的大小,從而幫助開發(fā)者進(jìn)行存儲(chǔ)優(yōu)化和數(shù)據(jù)庫(kù)表優(yōu)化。比如上面的t_int_complex_zerofill示例表,
我們很容易就能從各個(gè)數(shù)值列字段的ZEROFILL長(zhǎng)度中,累加計(jì)算出,每向表中增加1條數(shù)據(jù),就會(huì)用掉18個(gè)字節(jié)的存儲(chǔ)空間,公式如下:
TINYINT(1) + SMALLINT(2) + MEDIUMINT(3) + INT(4) + BIGINT(8) = 18字節(jié)
在實(shí)際的數(shù)據(jù)庫(kù)設(shè)計(jì)開發(fā)中,每位設(shè)計(jì)者的觀點(diǎn)和想法都不盡相同,都有自己的設(shè)計(jì)考量。關(guān)于Int數(shù)值類型的字段設(shè)計(jì),究竟Int(4)和Int(11)誰更好更美呢?作為開發(fā)人員的您,又是怎么看待它們的呢?


















































