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