MySQL不同存儲引擎可能會有不同。下面的內(nèi)容以InnoDB為主。
選擇數(shù)據(jù)類型的步驟
- 確定合適的大類型:數(shù)字、字符串、時間、二進(jìn)制
- 確定具體的類型:有無符號、取值范圍、變長定長等。
整數(shù)類型
類型 | 字節(jié)數(shù) | 范圍 |
---|---|---|
TNIYINT | 1 | -128~127 |
SMALLINT | 2 | -32767~32768 |
MEDIUMINT | 3 | -8388608~8388607 |
INT | 4 | -2147483648~2147483647 |
BIGINT | 8 | -9223372036854775808~9223372036854775807 |
- 每個整數(shù)類型都有對應(yīng)的無符號(UNSIGNED)類型。
- 建議使用TINYINT代替ENUM。
- 避免使用整數(shù)的顯示寬度。
實數(shù)類型
類型 | 字節(jié) | 備注 |
---|---|---|
FLOAT | 4 | 單精度浮點數(shù) |
DOUBLE | 8 | 雙精度浮點數(shù) |
DECIMAL | 可變 | 高精度定點數(shù) |
- DECIMAL只是一種存儲格式,MySQL以二進(jìn)制的合適存儲DECIMAL類型的列。在計算中,DECIMAL會轉(zhuǎn)換成DOUBLE。
- 不建議指定浮點數(shù)的精度。
- 不建議使用DECIMAL。
- 建議要存儲的實數(shù)乘以相應(yīng)的倍數(shù),使用整數(shù)類型運算和存儲。
字符串類型
VARCHAR vs CHAR
類型 | 最大長度 | 備注 |
---|---|---|
CHAR(size) | 255字節(jié) | 定長。size指定的是字符數(shù),不是字節(jié)數(shù)。 |
VARCHAR(size) | 65532字節(jié) | 變長。size指定的是字符數(shù),不是字節(jié)數(shù)。 |
-
適用VARCHAR:
- 字符串地最大長度比平均長度大很多;
- 列更新很少,所以碎片不是問題;
- 使用像UTF8這樣復(fù)雜地字符集,每個字符都可能使用不同的字節(jié)數(shù)進(jìn)行存儲。
-
適用CHAR:
- 短字符串;
- 所有值都接近一個長度;
- 經(jīng)常變更的列,這樣不易產(chǎn)生碎片;
CHAR類型的列,原字符串末尾的空格會被“干掉”,再填充空格。MySQL檢索CHAR不會使用末尾的空格。(列是定長的,MySQL沒有存儲寫入的字符串有多長,只好一刀切,末尾的空格都忽略掉。)
VARCHAR末尾的空格不會被“干掉”,檢索的時候會用到。(MySQL存儲了寫入的字符串的長度,這樣可以知道字符串末尾有多少各空格是你寫入的。)
VARCHAR(5)和VARCHAR(200),如果都只存了"abc",它們有什么不同呢?實際上,MySQL會分配固定大小地內(nèi)存塊來保存內(nèi)部值,因此VARCHAR(200)的列盡管只存了和VARCHAR(5)一樣的字符串,但是分配的內(nèi)存可能會大得多。
BINARY vs VARBINARY
類型 | 最大長度 | 備注 |
---|---|---|
BINARY | 255 | 定長 |
VARBINARY | 65535 | 變長 |
- BINARY和VARBINARY與CHAR和VARCHAR非常類似。
- BINARY和VARBINARY存儲的是二進(jìn)制字符串,與字符集無關(guān)。
- BINARY的末尾會被填充\0,并且會加入檢索。
BLOB vs TEXT
L表示數(shù)據(jù)的長度。
L+x表示存儲需要的空間。
類型 | 存儲 |
---|---|
TINYBLOB | L+1 bytes, L < 2^8 |
SMALLBLOB/BLOB | L+2 bytes, L < 2^16 |
MEDIUMBLOB | L+3 bytes, L < 2^24 |
LONGBLOB | L+4 bytes, L < 2^32 |
TINYTEXT | L+1 bytes, L < 2^8 |
SMALLTEXT/TEXT | L+2 bytes, L < 2^16 |
MEDIUMTEXT | L+3 bytes, L < 2^24 |
LONGTEXT | L+4 bytes, L < 2^32 |
- BLOB系列存儲二進(jìn)制字符串,與字符集無關(guān)。
- TEXT系列存儲非二進(jìn)制字符串,與字符集相關(guān)。
- 一般情況下,你可以認(rèn)為BLOB是一個更大的VARBINARY;TEXT是一個更大的VARCHAR。
- MySQL只能對BLOB和TEXT的前面max_sort_length各字符進(jìn)行排序和索引。
- BLOB和TEXT都不能有default value。
- 當(dāng)BLOB和TEXT的長度太大時,InnoDB會使用專門的“外部”存儲區(qū)域來進(jìn)行存儲。
日期和時間類型
類型 | 大小 |
---|---|
TIMESTAMP | 4字節(jié) |
DATETIME | 8字節(jié) |
- MySQL能存儲的最小時間粒度為秒。
- TIMESTAMP是UTC時間戳,與時區(qū)相關(guān)。
- DATETIME的存儲格式是一個YYYYMMDDHHmmSS的整數(shù),與時區(qū)無關(guān),你存了什么,讀出來就是什么。
- DATETIME的存儲范圍大于TIMESTAMP。
- TIMESTAMP的列可以自動更新。
- 除非有特殊需求,否則建議使用TIMESTAMP。
ENUM、SET、BIT
- ENUM列允許在列中存儲一組定義值中的單個值。
- SET列允許在列中存儲一組定義值中的一個或多個值。
- BIT在InnoDB中其實是一個最小的整數(shù)類型。而MySQL在檢索BIT的時候會將其當(dāng)做字符串,而不是整數(shù),這可能會導(dǎo)致一些奇怪的行為。
- 不建議使用這三個類型:用整數(shù)代替。
一些原則
- 選擇最小的滿足需求的數(shù)據(jù)類型。
一般情況下,應(yīng)該盡量使用可以正確存儲數(shù)據(jù)的最小數(shù)據(jù)類型。
簡單就好。
比如,用MySQL的內(nèi)建類型date, time, datetime來存儲時間,而不是使用字符串;用INT UNSIGNED來存儲IPv4地址。
如何存儲IPv6的地址?IPv6地址128bit,MySQL最大的整數(shù)類型BIGINT只有64bit。可以將其存儲成定長(16字節(jié))的二進(jìn)制字符?
- 盡量避免使用NULL。