在MySQL 中有兩種數(shù)值類型,整型和實(shí)數(shù)(即帶有小數(shù)的數(shù)字)。整型可以通過 TINYINT、SMALLINT、MEDIUMINT、INT 或 BIGINT 表示,分別對應(yīng)8bit、16bit、24bit、32bit 和64bit 的存儲(chǔ)空間。實(shí)數(shù)可以通過 FLOAT、DOUBLE 和 DECIMAL 表示,其中 FLOAT 和 DOUBLE 即通常所說的浮點(diǎn)數(shù),由于計(jì)算機(jī)二進(jìn)制存儲(chǔ)的精度問題,其計(jì)算得到的是近似的結(jié)果。
整型字段類型設(shè)計(jì)
整型可以選擇是否是無符號數(shù),這樣可以禁止使用負(fù)數(shù),并且可以將存儲(chǔ)的最大值翻倍,例如 TINYINT UNSIGNED類型的字段可以存儲(chǔ)的值的范圍是0-255,而不是有符號的-128-127。使用無符號還是有符號取決與字段類型的范圍,但是如果確定字段是無符號的,那么優(yōu)先選擇無符號類型,因?yàn)樽畲笾捣犊梢栽谝欢ǔ潭壬媳苊馐褂酶蟠鎯?chǔ)空間的整型類型。
MySQL 允許我們指定整型的寬度,例如 INT(11)。這對于大部分應(yīng)用并沒有太大意義——實(shí)際上 MySQL 并不會(huì)限制合法值的范圍,也就是即便指定為 INT(11),實(shí)際上只要數(shù)值類型的存儲(chǔ)空間足夠,也可以存儲(chǔ)超過設(shè)定寬度的整型,例如 INT(12)的數(shù)字也可能可以存儲(chǔ)到 INT(11)類型的字段中。對于存儲(chǔ)和計(jì)算而言,INT(1)和 INT(20)是等效的。
如果確實(shí)要考慮性能,應(yīng)該是根據(jù)業(yè)務(wù)真實(shí)的數(shù)值范圍來確定使用整型字段類型,原則是只要字段類型不會(huì)超過業(yè)務(wù)系統(tǒng)的數(shù)值最大值,那么盡可能地選擇低存儲(chǔ)長度的整型類型。如果是無符號的數(shù)值,那就盡量使用無符號屬性。例如,假設(shè)使用整型替代枚舉的話,如果枚舉數(shù)量不超過255個(gè),那就優(yōu)先使用 UNSIGNED TINYINT 類型。
實(shí)數(shù)
實(shí)數(shù)不僅僅可以用來存儲(chǔ)浮點(diǎn)數(shù),實(shí)際上還可以使用 DECIMAL 類型來存儲(chǔ)超出 BIGINT 類型的數(shù)值。對于 浮點(diǎn)數(shù),MySQL 支持精確浮點(diǎn)數(shù)類型和不精確浮點(diǎn)數(shù)。
FLOAT 和 DOUBLE 類型支持標(biāo)準(zhǔn)數(shù)學(xué)運(yùn)算的近似運(yùn)算,浮點(diǎn)數(shù)的實(shí)際計(jì)算結(jié)果的精確度依賴于實(shí)現(xiàn)浮點(diǎn)數(shù)的平臺。DECIMAL 類型用于存儲(chǔ)精確的浮點(diǎn)數(shù),在 MySQL 5.0以后,DECIMAL 也支持精確的數(shù)學(xué)運(yùn)算(更早的版本實(shí)際上是使用浮點(diǎn)數(shù)來進(jìn)行 DECIMAL 運(yùn)算的)。但是,由于 CPU 本身不能直接精確計(jì)算浮點(diǎn)數(shù),因此 DECIMAL 數(shù)據(jù)類型的計(jì)算速度會(huì)比浮點(diǎn)數(shù)要慢。
浮點(diǎn)數(shù)和 DECIMAL 都支持指定精度。DECIMAL 類型的可以分別指定小數(shù)點(diǎn)前后最大的數(shù)字位數(shù),這會(huì)影響數(shù)據(jù)列的存儲(chǔ)空間占用。MySQL5.0版本以后將數(shù)字位以二進(jìn)制形式存儲(chǔ)(每9位數(shù)使用4個(gè)字節(jié)存儲(chǔ))。例如 DECIMAL(18, 9)將在小數(shù)點(diǎn)兩側(cè)均為9位數(shù)字,算上小數(shù)點(diǎn)(占一個(gè)字節(jié)),總共需要9個(gè)字節(jié)來存儲(chǔ)。DECIMAL 最大的數(shù)字位數(shù)是65(包含小數(shù)位和整數(shù)位),例如下面的表表創(chuàng)建語句會(huì)報(bào)錯(cuò)提示#1426 - Too-big precision 66 specified for 'number'. Maximum is 65.
:
CREATE TABLE t_numbers (
id INT(11) AUTO_INCREMENT PRIMARY KEY,
number DECIMAL(66,1)
);
對于 FLOAT 和 DOUBLE類型,也可以類似 DECIMAL 那種方式指定整數(shù)位和小數(shù)位來確定存儲(chǔ)范圍和精度。不同的長度會(huì)使得 MySQL默認(rèn)選擇不同的數(shù)據(jù)類型并使用近似值存儲(chǔ)數(shù)據(jù)。FLOAT 類型的存儲(chǔ)長度固定為4個(gè)字節(jié), DOUBLE 類型的存儲(chǔ)長度固定為8個(gè)字節(jié)。精度是不確定的,指定精度對存儲(chǔ)空間并沒有幫助,因此從計(jì)算準(zhǔn)確度考慮,建議是不要指定精度。在內(nèi)部計(jì)算的時(shí)候,MySQL 會(huì)選擇使用 DOUBLE類型計(jì)算 FLOAT 類型的數(shù)據(jù)。
由于 DECIMAL 占據(jù)的空間更大以及計(jì)算資源消耗也更大,因此建議只有在需要精確表示數(shù)值的情況下選擇使用 DECIMAL(例如金融數(shù)據(jù),如金額)。如果考慮計(jì)算性能,也可以考慮使用 BIGINT 來存儲(chǔ)精確的浮點(diǎn)數(shù),例如將金額統(tǒng)一乘以固定的倍數(shù)轉(zhuǎn)換為 BIGINT 進(jìn)行運(yùn)算,這種方式的計(jì)算效率和存儲(chǔ)空間都會(huì)更小。