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