MySQL常用資料型別及細節
MySQL的資料型別
型別 | 型別舉例 |
---|---|
整數型別 | TINYINT、SMALLINT、MEDIUMINT、INT(或INTEGER)、BIGINT |
浮點型別 | FLOAT、DOUBLE |
定點數型別 | DECIMAL |
位型別 | BIT |
日期時間型別 | YEAR、TIME、DATE、DATETIME、TIMESTAMP |
文字字串型別 | CHAR、VARCHAR、TINYTEXT、TEXT、MEDIUMTEXT、LONGTEXT |
列舉型別 | ENUM |
集合型別 | SET |
二進位制字串類 | BINARY、VARBINARY、TINYBLOB、BLOB、MEDIUMBLOB、LONGBLOB |
JSON型別 | JSON物件、JSON陣列 |
空間資料型別 | 單值型別:GEOMETRY、POINT、LINESTRING、POLYGON;集合型別:MULTIPOINT、MULTILINESTRING、MULTIPOLYGON、 |
- 常見資料型別的屬性
MySQL關鍵字 | 含義 |
---|---|
NULL | 資料列可包含NULL值 |
NOT NULL | 資料列不允許包含NULL值 |
DEFAULT | 預設值 |
PRIMARY KEY | 主鍵 |
AUTO_INCREMENT | 自動遞增,適用於整數型別 |
UNSIGNED | 無符號 |
CHARACTER SET name | 指定一個字符集 |
1 整數型別
TINYINT、SMALLINT、MEDIUMINT、INT(INTEGER)和 BIGINT
整數型別 | 位元組 |
---|---|
TINYINT | 1 |
SMALLINT | 2 |
MEDIUMINT | 3 |
INT(INTEGER) | 4 |
BIGINT | 8 |
1.1 可選屬性
1.1.1 M
M
: 表示顯示寬度,M的取值範圍是(0, 255),該功能需要搭配“ZEROFILL
”使用
從MySQL 8.0.17開始,整數資料型別不推薦使用顯示寬度屬性
整型資料型別可以在定義表結構時指定所需要的顯示寬度,如果不指定,則系統為每一種型別指定預設的寬度值
1.1.2 UNSIGNED
UNSIGNED
1.1.3 ZEROFILL
ZEROFILL
:零填充
2 浮點型別
FLOAT、DOUBLE、REAL
整數型別 | 位元組 |
---|---|
FLOAT | 4 |
DOUBLE | 8 |
2.1 精度誤差
浮點數型別有個缺陷,就是不精準
在程式設計中,如果用到浮點數,要特別注意誤差問題,因為浮點數是不準確的,所以我們要避免使用“=”來判斷兩個數是否相等。同時,在一些對精確度要求較高的專案中,千萬不要使用浮點數,不然會導致結果錯誤,甚至是造成不可挽回的損失。
那麼,MySQL 有沒有精準的資料型別呢?當然有,這就是定點數型別: DECIMAL
。
從MySQL 8.0.17開始,
FLOAT(M,D)
和DOUBLE(M,D)
用法在官方文件中已經明確不推薦使用。另外,關於浮點型的UNSIGNED
也不推薦使用了
3 定點數型別
MySQL中的定點數型別只有 DECIMAL 一種型別
DECIMAL(M,D)
的方式表示高精度小數
3.1 資料精度說明
M
稱為 精度 ,D
稱為 標度 。(M,D)
中 M = 整數位 + 小數位
,D = 小數位
。 0<=M<=65,0<=D<=30
。
例如,定義DECIMAL(5,2)
的型別,表示該列取值範圍是-999.99~999.99
。
3.2 型別介紹
-
DECIMAL(M,D)
的最大取值範圍與DOUBLE
型別一樣,但是有效的資料範圍是由M
和D
決定的。 - 定點數在MySQL內部是以 字串 的形式進行儲存,這就決定了它一定是精準的
- 當DECIMAL型別不指定精度和標度時,其預設為
DECIMAL(10,0)
。當資料的精度超出了定點數型別的精度範圍時,則MySQL同樣會進行四捨五入處理。 - DECIMAL可以新增
UNSIGNED
屬性
4 位型別
BIT
BIT型別中儲存的是二進位制值,類似010110。
BIT(M)
長度 | 長度範圍 | 佔用空間 |
---|---|---|
M | 1 <= M <= 64 | 約為 (M + 7) / 8 個位元組 |
BIT
型別,如果沒有指定(M)
,預設是1位。這個1位,表示只能存1位的二進位制值。
使用b+0查詢資料時,可以直接查詢出儲存的十進位制資料的值
select b + 0 from table;
5 日期與時間型別
MySQL不同的版本可能有所差異
MySQL8.0版本支援的日期和時間型別主要有:YEAR型別、TIME型別、DATE型別、DATETIME型別和TIMESTAMP型別
-
YEAR
型別通常用來表示年 -
DATE
型別通常用來表示年、月、日 -
TIME
型別通常用來表示時、分、秒 -
DATETIME
型別通常用來表示年、月、日、時、分、秒 -
TIMESTAMP
型別通常用來表示帶時區的年、月、日、時、分、秒
5.1 TIMESTAMP
TIMESTAMP
型別也可以表示日期時間,其顯示格式與DATETIME
型別相同,都是 YYYY-MM-DD HH:MM:SS
,需要4個位元組的儲存空間。
但是TIMESTAMP
儲存的時間範圍比DATETIME
要小很多,只能儲存“1970-01-01 00:00:01 UTC”到“2038-01-19 03:14:07 UTC”之間的時間
儲存資料的時候需要對當前時間所在的時區進行轉換,查詢資料的時候再將時間轉換回當前的時區。因此,使用TIMESTAMP儲存的同一個時間值,在不同的時區查詢時會顯示不同的時間。
5.2 TIMESTAMP與DATETIME的區別
-
TIMESTAMP
儲存空間比較小,表示的日期時間範圍也比較小 - 底層儲存方式不同,
TIMESTAMP
底層儲存的是毫秒值,距離1970-1-1 0:0:0 0毫秒的毫秒值。 - 兩個日期比較大小或日期計算時,
TIMESTAMP
更方便、更快。 -
TIMESTAMP
和時區有關。TIMESTAMP
會根據使用者的時區不同,顯示不同的結果。而DATETIME
則只能反映出插入時當地的時區,其他時區的人檢視資料必然會有誤差的。
6 文字字串型別
MySQL中,文字字串總體上分為 CHAR 、 VARCHAR 、 TINYTEXT 、 TEXT 、 MEDIUMTEXT 、LONGTEXT 、 ENUM 、 SET 等型別。
6.1 CHAR與VARCHAR
型別 | 特點 | 長度 | 長度範圍 | 佔用的儲存空間 |
---|---|---|---|---|
CHAR(M) | 固定長度 | M | 0 <= M <= 255 | M個位元組 |
VARCHAR(M) | 可變長度 | M | 0 <= M <= 65535 | (實際長度 + 1)個位元組 |
6.1.1 CHAR
-
CHAR(M)
型別一般需要預先定義字串長度。如果不指定(M),則表示長度預設是1個字元。 - 如果儲存時,資料的實際長度比CHAR型別宣告的長度小,則會在 右側填充 空格以達到指定的長度。當MySQL檢索CHAR型別的資料時,CHAR型別的欄位會去除尾部的空格。
- 定義CHAR型別欄位時,宣告的欄位長度即為CHAR型別欄位所佔的儲存空間的位元組數。
6.1.2 VARCHAR
- VARCHAR(M) 定義時, 必須指定 長度M,否則報錯。
- 檢索VARCHAR型別的欄位資料時,會保留資料尾部的空格。VARCHAR型別的欄位所佔用的儲存空間為字串實際長度加1個位元組。
#Column length too big for column 'NAME' (max = 21845);
CREATE TABLE test_varchar2(
NAME VARCHAR(65535) #錯誤
);
6.1.3 哪些情況使用CHAR或VARCHAR更好
具體儲存引擎中的情況:
-
MyISAM
資料儲存引擎和資料列:MyISAM資料表,最好使用固定長度(CHAR)的資料列代替可變長度(VARCHAR)的資料列。這樣使得整個表靜態化,從而使 資料檢索更快 ,用空間換時間。 -
MEMORY
儲存引擎和資料列:MEMORY資料表目前都使用固定長度的資料行儲存,因此無論使用CHAR或VARCHAR列都沒有關係,兩者都是作為CHAR型別處理的。 -
InnoDB
儲存引擎,建議使用VARCHAR型別。因為對於InnoDB資料表,內部的行儲存格式並沒有區分固定長度和可變長度列(所有資料行都使用指向資料列值的頭指標),而且主要影響效能的因素是資料行使用的儲存總量,由於char平均佔用的空間多於varchar,所以除了簡短並且固定長度的,其他考慮varchar。這樣節省空間,對磁碟I/O和資料儲存總量比較好。
6.2 TEXT型別
在MySQL中,TEXT用來儲存文字型別的字串,總共包含4種類型,分別為TINYTEXT、TEXT、 MEDIUMTEXT 和 LONGTEXT 型別。
在向TEXT型別的欄位儲存和查詢資料時,系統自動按照實際長度儲存,不需要預先定義長度。這一點和VARCHAR型別相同。
每種TEXT型別儲存的資料長度和所佔用的儲存空間不同,如下:
型別 | 特點 | 長度 | 長度範圍 | 佔用的儲存空間 |
---|---|---|---|---|
TINYTEXT | 小文字、可變長度 | L | 0 <= L <= 255 | L + 2 個位元組 |
TEXT | 文字、可變長度 | L | 0 <= L <= 65535 | L + 2 個位元組 |
MEDIUMTEXT | 中等文字、可變長度 | L | 0 <= L <= 16777215 | L + 3 個位元組 |
LONGTEXT | 大文字、可變長度 | L | 0 <= L <= 4GB | L + 4 個位元組 |
- 由於實際儲存的長度不確定,MySQL不允許TEXT型別的欄位做主鍵。遇到這種情況,你只能採用CHAR(M),或者 VARCHAR(M)
- 跟VARCHAR一樣,在儲存和查詢資料時,不會刪除資料尾部的空格
6.2.1 使用TEXT型別的經驗
- TEXT文字型別,可以存比較大的文字段,搜尋速度稍慢,因此如果不是特別大的內容,建議使用CHAR, VARCHAR來代替
- 還有TEXT型別不用加預設值,加了也沒用
- 而且text和blob型別的資料刪除後容易導致“空洞”,使得檔案碎片比較多,所以頻繁使用的表不建議包含TEXT型別欄位,建議單獨分出去,單獨用一個表
6.3 ENUM型別
列舉型別
ENUM型別的取值範圍需要在定義欄位時進行指定
範圍 | 佔用的儲存空間 |
---|---|
1 <= L <= 65535 | 1或2個位元組 |
- 當ENUM型別包含1~255個成員時,需要1個位元組的儲存空間;
- 當ENUM型別包含256~65535個成員時,需要2個位元組的儲存空間。
- ENUM型別的成員個數的上限為65535個。
6.3.1 使用
CREATE TABLE test_enum(
season ENUM('春','夏','秋','冬','unknow')
);
INSERT INTO test_enum VALUES('春'),('秋');
# 忽略大小寫
INSERT INTO test_enum VALUES('UNKNOW');
# 允許按照角標的方式獲取指定索引位置的列舉值
INSERT INTO test_enum VALUES('1'),(3);
# Data truncated for column 'season' at row 1
INSERT INTO test_enum VALUES('ab');
# 當ENUM型別的欄位沒有宣告為NOT NULL時,插入NULL也是有效的
INSERT INTO test_enum VALUES(NULL);
小結
在定義資料型別時,如果確定是 整數
,就用 INT
; 如果是 小數
,一定用定點數型別DECIMAL(M,D)
; 如果是日期與時間,就用 DATETIME
。
阿里巴巴《Java開發手冊》之MySQL資料庫:
- 任何欄位如果為非負數,必須是
UNSIGNED
-
【 強制 】
小數型別為 DECIMAL,禁止使用 FLOAT 和 DOUBLE。- 說明:在儲存的時候,FLOAT 和 DOUBLE 都存在精度損失的問題,很可能在比較值的時候,得到不正確的結果。如果儲存的資料範圍超過 DECIMAL 的範圍,建議將資料拆成整數和小數並分開儲存。
-
【 強制 】
如果儲存的字串長度幾乎相等,使用 CHAR 定長字串型別。 -
【 強制 】
VARCHAR 是可變長字串,不預先分配儲存空間,長度不要超過 5000。如果儲存長度大於此值,定義欄位型別為 TEXT,獨立出來一張表,用主鍵來對應,避免影響其它欄位索引效率。