天天看點

MySQL全面瓦解3:資料類型介紹與分析

概述

MySQL支援很多資料類型,以便我們能在複雜的業務場景中支援各種各樣的資料格式,存儲适當的資料内容。我們在設計資料庫時,正确的使用資料庫類型對整個資料庫的整潔和高效,會有很大的幫助。

目前常用的資料類型大緻上可以分為4大類:整數類型、浮點數類型、字元串(字元)類型、日期/時間類型。詳細如下

4大類 主要類型
整數類型 tinyint 、 smallint 、 mediumint 、 int 、 bigint
浮點數類型 float 、 double 、 decimal
字元串(字元)類型 char 、 varchar 、 tinyblob 、 blob 、 mediumblob 、 longblob 、tinytext 、 text 、 mediumtext 、 longtext
日期/時間類型 Date 、 DateTime 、 TimeStamp 、 Time 、 Year

數值類型

MySQL支援所有标準SQL數值資料類型,包括嚴格數值資料類型(INTEGER、SMALLINT、DECIMAL和NUMERIC),還有近似數值資料類型(FLOAT、REAL和DOUBLE PRECISION),是以MySQL中資料類型是豐富且完整的。

而作為SQL标準的擴充,MySQL也支援整數類型TINYINT、MEDIUMINT和BIGINT。在下面的表格中,我們總結了5個整數類型的存儲大小和取值範圍。

類型 位元組數 有符号值範圍 無符号值範圍 作用
TINYINT 1 byte (-128,127)   (0,255) 小整數值
SMALLINT 2 bytes (-32 768,32 767) (0,65 535) 大整數值
MEDIUMINT 3 bytes (-8 388 608,8 388 607) (0,16 777 215)
INT或INTEGER 4 bytes (-2 147 483 648,2 147 483 647) (0,4 294 967 295)
BIGINT 8 bytes (-9,223,372,036,854,775,808,9 223 372 036 854 775 807) (0,18 446 744 073 709 551 615) 極大整數值

我們建立表賦予的類型預設是有符号類型的,無符号的需要在類型需要後面跟上unsigned 标記,上面的資料範圍是根據位元組對應二進制換算,比如一個位元組轉化為十進制最大為255(11111111),最小為0(00000000),具體可以去查下二進制表示相關資料。

測試一下:

1 mysql> create table tinyintdemo(
 2   tiny TINYINT,
 3   tinyunsi TINYINT UNSIGNED
 4 );
 5 Query OK, 0 rows affected
 6 
 7 mysql> insert into tinyintdemo values(-128,-128);
 8 1264 - Out of range value for column 'tinyunsi' at row 1
 9 mysql> insert into tinyintdemo values(-128,0);
10 Query OK, 1 row affected
11 
12 mysql> insert into tinyintdemo values(255,255);
13 1264 - Out of range value for column 'tiny' at row 1
14 mysql> insert into tinyintdemo values(127,255);
15 Query OK, 1 row affected      

 上面我們故意輸入不正确的值,無符号下我們輸入-128,預設有符号情況下我們輸入255,都會提示 Out of range,超出範圍。

1 mysql> select *  from  tinyintdemo;
2 +------+----------+
3 | tiny | tinyunsi |
4 +------+----------+
5 | -128 |        0 |
6 |  127 |      255 |
7 +------+----------+
8 2 rows in set      

另外需注意的點:我們經常在建立表的時候定義字段為int(n),比如int(11) , 或者bitint(19) , 其實這不是描述字段長度的意思,在int(n)中,int占據的位元組是固定4個,是以他的範圍也固定是在 (-2 147 483 648,2 147 483 647) 之間,

并不會因為n的長度是多少而改變,而n的目的是為了表實顯示寬度用的,在顯示寬度不足的時候補充0。

再測試一下:

1 mysql> CREATE TABLE lengthdemo (
 2        `nor` int,
 3        `norlen` int(8),
 4        `norfill` int(8) zerofill
 5 );
 6 Query OK, 0 rows affected
 7 
 8 mysql> insert into lengthdemo values(12345,12345,12345);
 9 Query OK, 1 row affected
10 
11 mysql> select * from lengthdemo;
12  
13 +-------+--------+---------+
14 | nor   | norlen | norfill |
15 +-------+--------+---------+
16 | 12345 |  12345 |00012345 |
17 +-------+--------+---------+
18 1 row in set
19 
20 mysql> show create table lengthdemo;
21 +------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
22 | Table      | Create Table                                                                                                                                                                   |
23 +------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
24 | lengthdemo | CREATE TABLE `lengthdemo` (
25   `nor` int(11) DEFAULT NULL,
26   `norlen` int(8) DEFAULT NULL,
27   `norfill` int(8) unsigned zerofill DEFAULT NULL
28 ) ENGINE=InnoDB DEFAULT CHARSET=latin1 |
29 +------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
30 1 row in set      

從這個執行結果中,我們可以總結如下:

1、n的值不管填寫多少,int類型隻占據4個位元組。

2、如果設定了n的顯示寬度之後,再加上unsigned zerofill,顯示寬度不足的用0補足,超過則直接顯示完整數值。

3、加 zerofill屬性的字段,會預設為 unsigned 無符号類型。

浮點類型 

float數值類型表示單精度浮點數值,double數值類型表示雙精度浮點數值,float和double都是浮點型,而decimal是定點型。浮點型和定點型可以用類型名稱後加(M,D)來表示,M表示該值的總共長度,D表示小數點後面的長度,M和D又稱為精度和标度。

float和double在不指定精度時,預設會按照實際的精度來顯示,而DECIMAL在不指定精度時,預設整數為10,小數為0。 

大小
FLOAT (-3.402 823 466 E+38,-1.175 494 351 E-38),0,(1.175 494 351 E-38,3.402 823 466 351 E+38) 0,(1.175 494 351 E-38,3.402 823 466 E+38)

單精度

浮點數值

DOUBLE (-1.797 693 134 862 315 7 E+308,-2.225 073 858 507 201 4 E-308),0,(2.225 073 858 507 201 4 E-308,1.797 693 134 862 315 7 E+308) 0,(2.225 073 858 507 201 4 E-308,1.797 693 134 862 315 7 E+308) 雙精度
DECIMAL 對DECIMAL(M,D) ,如果M>D,為M+2否則為D+2 依賴于M和D的值 小數值

浮點型和定點型可以用類型名稱後加(M,D)來表示,M表示該值的總共長度,D表示小數點後面的長度,M和D又稱為精度和标度。

float和double在不指定精度時,預設會按照實際的精度來顯示,而DECIMAL在不指定精度時,預設隻取整數,小數丢棄。

同樣的,我們來測試下三個類型的使用:

1 mysql> insert into accuracy values (1,1,1),(2.124,2.124,2.124),(3.125,3.125,3.125),(4.115,4.115,4.115),(5.136,5.136,5.136);
 2 Query OK, 5 rows affected, 4 warnings (0.07 sec)
 3 Records: 5  Duplicates: 0  Warnings: 4
 4 
 5 mysql> select * from accuracy;
 6 +------+------+------+
 7 | a    | b    | c    |
 8 +------+------+------+
 9 | 1.00 | 1.00 | 1.00 |
10 | 2.12 | 2.12 | 2.12 |
11 | 3.12 | 3.12 | 3.13 |
12 | 4.12 | 4.12 | 4.12 |
13 | 5.14 | 5.14 | 5.14 |
14 +------+------+------+
15 5 rows in set (0.00 sec)      

 從這個執行結果,總結如下:

1、c是decimal類型,采用的是四舍五入

2、a和b分别為float 和double,采用的是四舍六入五成雙

說明下四舍六入五成雙:5以下舍棄,5以上進位,遇到5的時候,如果5後面還有不為0的任何數字,進位,如果沒有,需要檢查5前面的數字,奇數進位,偶數丢棄,觀察結果中 3.125和4.115,可以得到規律。

我們再将浮點類型的(M,D)精度和标度都去掉,結果如下: 

1 mysql> create table accuracy2(a float,b double,c decimal);
 2 Query OK, 0 rows affected
 3 
 4 mysql> insert into accuracy2 values (1,1,1),(1.23,1.23,1.23);
 5 Query OK, 2 rows affected
 6 Records: 2  Duplicates: 0  Warnings: 1
 7 
 8 mysql> select * from accuracy2;
 9 +------+------+---+
10 | a    | b    | c |
11 +------+------+---+
12 |    1 |    1 | 1 |
13 | 1.23 | 1.23 | 1 |
14 +------+------+---+
15 2 rows in set      

總結如下:

如果浮點數float、double如果不寫精度和标度,則會按照實際的結果顯示,而decimal會将小數四舍五入,并且插入時發出警告資訊。

float,double等非标準類型,在DB中儲存的是近似值,而decimal則以字元串的形式儲存準确的數值,比如銀行、金融系統之類的對統計精度要求比較高的,建議采用decimal。 

日期和時間類型

表示時間值的日期和時間類型為DATETIME、DATE、TIMESTAMP、TIME和YEAR。每個時間類型有一個有效值範圍和一個"零"值,當指定不合法的MySQL不能表示的值時使用"零"值。

TIMESTAMP類型有專有的自動更新特性,将在後面描述。

值範圍 格式
DATE 3 bytes 1000-01-01/9999-12-31 YYYY-MM-DD 日期值
TIME '-838:59:59'/'838:59:59' HH:MM:SS 時間值或持續時間
YEAR 1 bytes 1901/2155 YYYY 年份值
DATETIME 8 bytes 1000-01-01 00:00:00/9999-12-31 23:59:59 YYYY-MM-DD HH:MM:SS 混合日期和時間值
TIMESTAMP 4 bytes

1970-01-01 00:00:00/2038

結束時間是第 2147483647 秒,中原標準時間 2038-1-19 11:14:07,格林尼治時間 2038年1月19日 淩晨 03:14:07

YYYYMMDD HHMMSS 混合日期和時間值,時間戳

字元串類型

字元串類型指CHAR、VARCHAR、BINARY、VARBINARY、BLOB、TEXT、ENUM和SET。

CHAR 0-255 bytes 定長字元串
VARCHAR 0-65535 bytes 變長字元串
TINYBLOB 不超過 255 個字元的二進制字元串
TINYTEXT 短文本字元串
BLOB 0-65 535 bytes 二進制形式的長文本資料
TEXT 長文本資料
MEDIUMBLOB 0-16 777 215 bytes 二進制形式的中等長度文本資料
MEDIUMTEXT 中等長度文本資料
LONGBLOB 0-4 294 967 295 bytes 二進制形式的極大文本資料
LONGTEXT 極大文本資料

注意點:

1、CHAR(N) 和 VARCHAR(N) 中N代表字元的個數,但并不代表位元組個數,比如 CHAR(10) 代表可以存儲 10 個字元。

2、CHAR 和VARCHAR類型類似,但它們儲存和檢索的方式不同,最大長度和是否尾部空格被保留等方面也不同,同時在存儲或檢索過程中不進行大小寫轉換。

如果存放的資料為固定長度的建議使用char類型,如:手機号碼、身份證等固定長度的資訊。

3、BINARY 和 VARBINARY 類似于 CHAR 和 VARCHAR,不同的是它們包含二進制字元串而不要非二進制字元串。它們包含位元組字元串而不是字元字元串。這說明它們沒有字元集,并且排序和比較基于列值位元組的數值。

4、BLOB是一個二進制大對象,可以容納可變數量的資料,包含4 種類型:TINYBLOB、BLOB、MEDIUMBLOB 和 LONGBLOB,差別是可容納存儲範圍不同。

5、TEXT 類型:TINYTEXT、TEXT、MEDIUMTEXT 和 LONGTEXT。對應的這 4 種 BLOB 類型,可存儲的最大長度不同,可根據實際業務場景的選擇。  

MySQL、Java類型對照

MySQL Type Name

Return value

ofGetColumnClassName

Returned as Java Class
BIT(1) (new in MySQL-5.0) BIT java.lang.Boolean

BIT( > 1) (new in MySQL-

5.0)

byte[]

java.lang.Boolean if the configuration

property tinyInt1isBit is set to true (the

default) and the storage size is 1,

or java.lang.Integer if not.

BOOL, BOOLEAN

See TINYINT, above as these are aliases

forTINYINT(1), currently.

SMALLINT[(M)]

[UNSIGNED]

SMALLINT [UNSIGNED]

java.lang.Integer (regardless if

UNSIGNED or not)

MEDIUMINT[(M)] MEDIUMINT [UNSIGNED]

java.lang.Integer, if

UNSIGNED java.lang.Long

INT,INTEGER[(M)] INTEGER [UNSIGNED] java.lang.Integer , if
BIGINT[(M)] [UNSIGNED] BIGINT [UNSIGNED]

java.lang.Long , if

UNSIGNED java.math.BigInteger

FLOAT[(M,D)] java.lang.Float
DOUBLE[(M,B)] java.lang.Double
DECIMAL[(M[,D])]

java.math.BigDecimal

a

java.sql.Date

Ja

java.sql.Timestamp
TIMESTAMP[(M)]
java.sql.Time

YEAR[(2|4)]

If yearIsDateType configuration property

is set to false, then the returned object type

is java.sql.Short . If set to true (the

default) then an object of type

java.sql.Date (with the date set to

January 1st, at midnight).

CHAR(M)

java.lang.String (unless the character

set for the column is BINARY, then byte[] is

returned.

VARCHAR(M) [BINARY]
BINARY(M) BINARY
VARBINARY(M) VARBINARY
java.lang.String
ENUM('value1','value2',...)
SET('value1','value2',...)

使用建議

不建議選擇較大的數值範圍,盡量選擇合适的資料範圍,越小的資料類型會更快,占用磁盤,記憶體和CPU緩存也更小。

越簡單的類型執行的成本越低,比如整型比字元類型操作代價要小得多,很多固定範圍的文本内容字段可以用整型表示。

盡量制定列為NOT NULL,有NULL的列值會使得索引、索引統計和值比較更加複雜。

浮點類型的建議統一選擇decimal,精度會好很多。

記錄時間的建議使用時間戳格式,存儲友善,索引高效

MySQL全面瓦解3:資料類型介紹與分析

架構與思維·公衆号:撰稿者為bat、位元組的幾位高階研發/架構。不做廣告、不賣課、不要打賞,隻分享優質技術

碼字不易,歡迎關注,歡迎轉載

作者:翁智華

出處:https://www.cnblogs.com/wzh2010/

本文采用「CC BY 4.0」知識共享協定進行許可,轉載請注明作者及出處。