【深入淺出MySQL】之數據類型介紹
- MySQL中常見的數據類型一覽
- 為什么需要如此多的數據類型
- 數值類型
- BIT(M)類型
- INT類型
- TINYINT類型
- BIGINT類型
- 浮點數類型
- float類型
- DECIMAL(M,D)類型
- 區別總結
- 字符串類型
- CHAR類型
- VARCHAR(M)類型
- 日期和時間類型
- enum和set類型
前言:MySQL是一種廣泛使用的關系型數據庫管理系統,它提供了多種數據類型供開發者去選擇,以此來滿足不同的場景。
MySQL中常見的數據類型一覽
類別 | 數據類型 | 描述 | 存儲范圍/長度 | 常見用途 |
---|---|---|---|---|
數值類型 | TINYINT | 非常小的整數 | -128 到 127(有符號);0 到 255(無符號) | 存儲小的整數,如狀態碼(0/1)、年齡等 |
BITM | 位類型,M 指定位數,默認值1 | M 的范圍(1~64) | 適用于需要存儲二進制信息的情況,例如標志位、布爾值數組等。通過使用 BIT 類型,可以更有效地存儲和操作位級別的數據。 | |
SMALLINT | 小整數 | -32,768 到 32,767(有符號);0 到 65,535(無符號) | 存儲中等范圍的整數,如計數器、小范圍的ID | |
MEDIUMINT | 中等大小的整數 | -8,388,608 到 8,388,607(有符號);0 到 16,777,215(無符號) | 存儲中等范圍的整數,較少使用 | |
INT / INTEGER | 標準整數 | -2,147,483,648 到 2,147,483,647(有符號);0 到 4,294,967,295(無符號) | 存儲常用整數,如用戶ID、訂單號等 | |
BIGINT | 大整數 | -9,223,372,036,854,775,808 到 9,223,372,036,854,775,807(有符號) | 存儲大范圍整數,如大型系統的ID、計數器 | |
FLOAT | 單精度浮點數 | 約 ±3.4E+38(7位有效數字) | 存儲近似數值,如價格、科學計算數據 | |
DOUBLE | 雙精度浮點數 | 約 ±1.79E+308(15位有效數字) | 存儲更高精度的近似數值,如金融數據、科學計算 | |
DECIMAL(M,D) | 定點數(精確小數) | M 是總位數,D 是小數位數,例如 DECIMAL(10,2) 存儲 8位整數+2位小數 | 存儲精確小數,如貨幣金額(避免浮點誤差) | |
字符串類型 | CHAR(M) | 固定長度字符串 | 0 到 255 個字符 | 存儲固定長度的字符串,如狀態碼、性別(‘M’/‘F’) |
VARCHAR(M) | 可變長度字符串 | 0 到 65,535 個字符(取決于字符集和存儲引擎) | 存儲可變長度的字符串,如用戶名、地址 | |
TINYTEXT | 短文本字符串 | 最大 255 個字符 | 存儲短文本,如備注、小段描述 | |
TEXT | 標準文本字符串 | 最大 65,535 個字符 | 存儲較長的文本,如文章內容、評論 | |
MEDIUMTEXT | 中等長度文本字符串 | 最大 16,777,215 個字符 | 存儲中等長度的文本,如長篇文章 | |
LONGTEXT | 超長文本字符串 | 最大 4,294,967,295 個字符 | 存儲超長文本,如日志文件、JSON 數據 | |
ENUM('value1', 'value2', ...) | 枚舉類型,只能從預定義值中選擇一個值 | 最多 65,535 個不同值 | 存儲固定選項,如狀態(‘active’/‘inactive’)、性別(‘male’/‘female’) | |
SET('value1', 'value2', ...) | 集合類型,可以選擇多個預定義值(以逗號分隔) | 最多 64 個不同值 | 存儲多選選項,如興趣(‘reading,swimming’) | |
日期和時間類型 | DATE | 日期 | 1000-01-01 到 9999-12-31 | 存儲日期,如生日、注冊日期 |
TIME | 時間 | -838:59:59 到 838:59:59 | 存儲時間,如一天中的時間點、持續時間 | |
DATETIME | 日期和時間組合 | 1000-01-01 00:00:00 到 9999-12-31 23:59:59 | 存儲完整的日期和時間,如創建時間、更新時間 | |
TIMESTAMP | 時間戳(從 1970-01-01 00:00:00 UTC 開始) | 1970-01-01 00:00:00 到 2038-01-19 03:14:07(UTC) | 存儲時間戳,常用于記錄數據更新時間(自動更新) | |
YEAR | 年份 | 1901 到 2155(4位格式);70 到 69(2位格式,1970-2069) | 存儲年份,如出生年份、發布年份 | |
其他類型 | BINARY(M) | 固定長度的二進制字符串 | 0 到 255 個字節 | 存儲固定長度的二進制數據,如校驗碼 |
VARBINARY(M) | 可變長度的二進制字符串 | 0 到 65,535 個字節 | 存儲可變長度的二進制數據,如小型文件 | |
BLOB | 二進制大對象 | 最大 65,535 個字節 | 存儲二進制數據,如圖片、文件 | |
MEDIUMBLOB | 中等長度的二進制大對象 | 最大 16,777,215 個字節 | 存儲中等大小的二進制數據,如較大的文件 | |
LONGBLOB | 超長二進制大對象 | 最大 4,294,967,295 個字節 | 存儲超大二進制數據,如視頻文件 | |
JSON | JSON 格式數據(MySQL 5.7+ 支持) | 最大 1GB(受限于存儲引擎) | 存儲 JSON 數據,如配置信息、動態字段 |
為什么需要如此多的數據類型
似乎單一數據類型如字符類型可以存儲所有的數據,但事實上,我們需要如此多的數據類型的原因有以下幾種:
- 數據的準確性與合法性需求:有時候我們描述某一個列時,如果這個列只能是整數,而不能出現小數點(如
id
),此時如果只有字符類型就滿足不了需求,而整數類型和浮點數類型的存在就可以有效防止非法的數據進入數據庫中。 - 性能上:
- 空間上:如果只有單一的
INT
類型的整數,有時候某些列的大小永遠不會超過某一個整數值,這個時候使用INT
就很浪費空間,所以使用 TINYINT 來存儲 0 到 255 范圍內的整數比使用 VARCHAR 更節省空間。 - 時間上:對于數值運算,直接使用數值類型而不是字符串類型進行計算會更加高效。這是因為數值類型可以直接參與算術運算,而字符串則需要先轉換成數值形式才能進行相應的操作,這增加了額外的處理開銷。
- 空間上:如果只有單一的
- 功能上:
- 日期時間處理:專門的日期時間類型(如
DATE
,TIME
,DATETIME
)提供了豐富的函數支持,方便進行日期計算、格式化輸出等操作。如果用字符串表示日期時間,則需要手動編寫代碼來進行這些操作,不僅復雜而且容易出錯。
- 日期時間處理:專門的日期時間類型(如
- 查詢優化:
- 索引利用:某些數據類型允許創建特定類型的索引(如全文索引適用于 TEXT 類型),從而提高查詢能力。如果所有數據都以字符串形式存儲,則可能無法充分利用這些高級索引功能。
數值類型
BIT(M)類型
BIT是位類型,其中
M
是位數,如果你想精確控制該列的位數,可以使用這個類型。
-
創建一個表
tt1
,表中有一個num
列,它的類型是BIT(1)
: -
表創建成功了:
-
向表中插入數據:
- 超過
1
就插入失敗,因為bit
位的位數位1,只能表示0
、1
。 - 但是發現一個很奇怪的現象,就算查表,1沒有顯示出來。
- 超過
-
這是因為
bit
類型是默認是按照ASCII
碼,1
對應的符號是不可顯示的特殊符號。 -
測試一下
bit
類型位數的邊界情況:create table tt3(num bit(65)); create table tt4(num bit(0));
[!tip]
如果我們有一些列,只需要
0
或者1
就可以使用bit(1)
,這樣非常節省空間。
INT類型
INT類型的范圍:-2,147,483,648 到 2,147,483,647(有符號);0 到 4,294,967,295(無符號)
這和我們C語言中的是相符的。
但C語言中溢出后會截斷,數據庫是否會這樣呢?
-
首先我們創建表
tt4
:create table tt4(num int);
-
查看表
tt4
:int
后面的數字的含義:這是表示的默認寬度,通常配合ZEROFILL
屬性使用,這個后面我們再談,和C語言中的printf
的格式控制符很像。
-
插入一個數字,我們測試
int
的邊界,插入2147483647
、2,147,483,648
,-2,147,483,648
、-2,147,483,649
:
TINYINT類型
TINYINT
也是整數類型,但是它只能表示-128 到 127(有符號),0 到 255(無符號)當你的列需要一個整數類型來表示,但是不會超過255
時就可以使用這個類型。
-
創建表
tt5
:create table tt5(num tinyint);
-
越界測試:
insert into tt5 values(128);
BIGINT類型
大整數類型,它能表示-9,223,372,036,854,775,808 到 9,223,372,036,854,775,807(有符號),適合做大型系統的
id
列的類型、計數器等。
-
創建表
tt6
:create table tt6(num bigint);
-
數據類型邊界測試:
insert into tt6 values(-9223372036854775808);
浮點數類型
float類型
語法(syntax):
float[(m, d)] [unsigned] : M指定顯示長度,d指定小數位數,占用空間4個
-
創建表
tt7
,它有一個num
列是float(5,2)
類型,長度為5,小數位數為2,它可以表示999.99 ~ -999.99
的值:create table tt7(float(5,2));
-
插入一些值觀察現象:
mysql> insert into tt7 values(999.99999999); ERROR 1264 (22003): Out of range value for column 'num' at row 1 mysql> insert into tt7 values(999.99); Query OK, 1 row affected (0.00 sec)mysql> insert into tt7 values(999.93); Query OK, 1 row affected (0.00 sec)mysql> insert into tt7 values(-999.999); ERROR 1264 (22003): Out of range value for column 'num' at row 1 mysql> insert into tt7 values(-999.99); Query OK, 1 row affected (0.00 sec)mysql> insert into tt7 values(-9999); ERROR 1264 (22003): Out of range value for column 'num' at row 1 mysql> insert into tt7 values(-99);Query OK, 1 row affected (0.00 sec) mysql> select * from tt7; +---------+ | num | +---------+ | 999.99 | | 999.93 | | -999.99 | | -99.00 | +---------+
- 可以看到依舊會發生越界的情況。
-
如果我們插入的值長度超過
M
,但是范圍又在此時[M,d]所限定的范圍內,就會發生四舍五入的情況:
DECIMAL(M,D)類型
M 是總位數,D 是小數位數,例如 DECIMAL(10,2) 存儲 8位整數+2位小數
聽上去好像和float
沒什么區別呀,我們來建個表插入數據看看:
-
創建表
tt8
,它有一列num,數據類型為decimal(5,2)
,存儲3位整數+2位小數:create table tt8(num decimal(5,2));
-
插入一些值,然后觀察現象:
insert into tt8 values(999.976) ...
- 它似乎也和
float
一樣也會進行越界判斷,也會四舍五入,那它們有什么區別呢?
區別總結
我們從實際的現象來觀察并思考為什么會這樣。
-
創建表
tt9
:create table tt9(num1 float(10,1),num2 decimal(10,1));
-
插入下面的值:
insert into tt9(999999998,999999998);
-
表中最終的結果:
mysql> select * from tt9; +--------------+-------------+ | num1 | num2 | +--------------+-------------+ | 1000000000.0 | 999999998.0 | +--------------+-------------+
- 居然!,
num1
被近似成了1000000000.0
,而且總長度是11位,我們不是規定了總長度嗎?這個num2
是正常顯示的。
- 居然!,
-
我們手動插入一下一行讓
num1
為1000000000.0
,看能否成功:mysql> insert into tt9 values(1000000000.0,999999998); ERROR 1264 (22003): Out of range value for column 'num1' at row 1
- 很明顯失敗了,
MySQL
報錯了。
- 很明顯失敗了,
總結:
FLOAT
是近似類型:它不保證精確存儲和顯示,可能會對大數值進行近似處理。DECIMAL
是精確類型:它嚴格按照定義的范圍和精度存儲和顯示數據。- 顯示寬度不受嚴格限制:FLOAT(M,D) 的定義主要用于限制存儲范圍(也就是限制用戶的),但實際顯示的寬可能會因為近似超出定義的范圍。
所以如果我們的列對數據的精確性要求很高,且是浮點數,就需要使用DECIMAL
類型。
字符串類型
CHAR類型
語法:char(L):固定長度字符串,不管用戶輸入的字符串的長度為多少,
MySQL
都會拿出L
的長度給該列,L
的最大值是255
。
[!caution]
MySQL
里面的一個長度就對應一個字符,不管你是中文、英文字符、還是特殊字符都只占一個長度單位,也就是說MySQL
對于字符長度有自己的標準。在 MySQL 中,字符長度單位指的是字符的數量,而不是字節數。但是,實際占用的存儲空間取決于字符集。
下面我們創建表,插入一些值來驗證一下:
-
創建表
tt10
:create table tt10(s char(5));
-
插入一些字符:
insert into tt10 values('你好世界呀'); insert into tt10 values('abcde'); insert into tt10 values('abcdef');
- 我們都知道實際上中文字符的存儲字節和英文字符的存儲字節一般是不同的,要看具體的存儲編碼,所以在 MySQL 中,字符長度單位指的是字符的數量,而不是字節數。
[!caution]
如果你插入的字符的長度比
L
小,MySQL
會自動填充空格。
VARCHAR(M)類型
varchar(L): 可變長度字符串,L表示字符長度,最大長度65535個字節
-
創建表
tt11
:create table tt11(s varchar(10));
-
插入一些字符串:
insert into tt11 values("111"); insert into tt11 values("1111111111");
[!caution]
變長并不是這個類型存儲的字符的長度可以超過用戶指定的長度
L
,而是當用戶實際存儲的字符長度沒有L
時,MySQL
不會使用空格填充,這樣節省了空間。
如何選擇char
和varchar
類型:
- 如果指定列的字符串長度是固定的,就使用
char
類型。 - 當存儲大量可變長度的字符串時,可以使用
varchar
來節省存儲空間。 CHAR
因為是定長的,存儲和檢索效率更高,尤其是在頻繁訪問和更新的場景中。VARCHAR
因為需要額外的長度信息,存儲和檢索效率略低,但在現代數據庫系統中,這種差異通常不明顯。
日期和時間類型
MySQL中日期類型(如
DATE
、DATETIME
、TIMESTAMP
等)是非常重要的數據類型。它們的存在是為了更高效地存儲、查詢和操作與時間相關的數據。
日期類型可以表示廣泛的日期范圍,遠超過普通字符串或數字能表達的范圍。例如:
DATE
類型支持從 ‘1000-01-01’ 到 ‘9999-12-31’ 的日期。DATETIME
和TIMESTAMP
支持精確到秒甚至微秒的時間點。
下面我們創建一個表,使用一下日期類型:
-
創建表
tt12
:create table tt12(d1 date,d2 datetime,t timestamp);
-
插入一些值:
insert into tt12 values('1922-01-22','1922-01-22 00:00:00',FROM_UNIXTIME(1));
-
TIMESTAMP
不支持直接插入原始的 Unix 時間戳(如1742947200
),需要通過FROM_UNIXTIME()
函數進行轉換。插入當前時間:可以使用NOW()
或CURRENT_TIMESTAMP
來插入當前時間。 -
DATETIME
存儲日期和時間。 -
DATE
只存儲日期。
-
enum和set類型
ENUM
(枚舉)類型是一種字符串對象,其值范圍必須來自一個預定義的列表。這些值是按定義順序排列的,并且只能選擇列表中的值之一。SET 類型是一種字符串對象,它可以包含零個或多個由逗號分隔的值,這些值來自于一個預定義的列表。與 ENUM 不同的是,SET 允許一個字段包含多個值。
使用介紹:
-
創建表
tt13
:create table tt13(identity enum('學生','老師','工人'), set permissions('write','read','exec'));
-
插入一些值:
mysql> insert into tt13 values('學生','write,res'); ERROR 1265 (01000): Data truncated for column 'permissions' at row 1 mysql> insert into tt13 values('學生','write,read'); Query OK, 1 row affected (0.00 sec)mysql> insert into tt13 values('學生','write'); Query OK, 1 row affected (0.00 sec)mysql> insert into tt13 values('學生,老師','write'); ERROR 1265 (01000): Data truncated for column 'identity' at row 1 mysql> insert into tt13 values('學生1','write'); ERROR 1265 (01000): Data truncated for column 'identity' at row 1
應用場景:
- 使用
ENUM
:- 當字段的值是單一選項時。
- 需要確保數據一致性且選項數量較少。
- 場景示例:性別、狀態、分類等。
- 使用
SET
:- 當字段的值是多個選項的組合時。
- 需要靈活的多選功能且選項數量較少。
- 場景示例:權限、興趣愛好、標簽等。