1. 程式人生 > 其它 >MySQL常用資料型別及細節

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型別一樣,但是有效的資料範圍是由MD決定的
  • 定點數在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,獨立出來一張表,用主鍵來對應,避免影響其它欄位索引效率。