1. 程式人生 > 其它 >第12章 MySQL資料型別精講

第12章 MySQL資料型別精講

第12章 MySQL資料型別精講


1. 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、GEOMETRYCOLLECTION

常見資料型別的屬性,如下:

MySQL關鍵字 含義
NULL 資料列可包含NULL值
NOT NULL 資料列不允許包含NULL值
DEFAULT 預設值
PRIMARY KEY 主鍵
AUTO_INCREMENT 自動遞增,適用於整數型別
UNSIGNED 無符號
CHARACTER SET name 指定一個字符集

2. 整數型別

2.1 型別介紹

整數型別一共有 5 種,包括 TINYINT、SMALLINT、MEDIUMINT、INT(INTEGER)和 BIGINT。

它們的區別如下表所示:

整數型別 位元組 有符號數取值範圍 無符號數取值範圍
TINYINT 1 -128~127 0~255
SMALLINT 2 -32768~32767 0~65535
MEDIUMINT 3 -8388608~8388607 0~16777215
INT、INTEGER 4 -2147483648~2147483647 0~4294967295
BIGINT 8 -9223372036854775808~9223372036854775807 0~18446744073709551615

2.2 可選屬性

整數型別的可選屬性有三個:

2.2.1 M

M: 表示顯示寬度,M的取值範圍是(0, 255)。例如,int(5):當資料寬度小於5位的時候在數字前面需要用字元填滿寬度。該項功能需要配合“ZEROFILL”使用,表示用“0”填滿寬度,否則指定顯示寬度無效。

如果設定了顯示寬度,那麼插入的資料寬度超過顯示寬度限制,會不會截斷或插入失敗?

答案:不會對插入的資料有任何影響,還是按照型別的實際寬度進行儲存,即顯示寬度與型別可以儲存的值範圍無關從MySQL 8.0.17開始,整數資料型別不推薦使用顯示寬度屬性。

整型資料型別可以在定義表結構時指定所需要的顯示寬度,如果不指定,則系統為每一種型別指定預設的寬度值。

舉例:

CREATE TABLE test_int1 ( x TINYINT, y SMALLINT, z MEDIUMINT, m INT, n BIGINT );

查看錶結構 (MySQL5.7中顯式如下,MySQL8中不再顯式範圍)

mysql> desc test_int1;
+-------+--------------+------+-----+---------+-------+
| Field | Type         | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+-------+
|   x   | tinyint(4)   | YES  |     | NULL    |       |
|  y   | smallint(6)  | YES  |     | NULL    |       |
|  z   | mediumint(9) | YES  |     | NULL    |       |
|  m   | int(11)      | YES  |     | NULL    |       |
|  n   | bigint(20)   | YES  |     | NULL    |       |
+-------+--------------+------+-----+---------+-------+
5 rows in set (0.00 sec)

TINYINT有符號數和無符號數的取值範圍分別為-128127和0255,由於負號佔了一個數字位,因此TINYINT預設的顯示寬度為4。同理,其他整數型別的預設顯示寬度與其有符號數的最小值的寬度相同。

舉例:

CREATE TABLE test_int2(
f1 INT,
f2 INT(5),
f3 INT(5) ZEROFILL
)

DESC test_int2;

INSERT INTO test_int2(f1,f2,f3)
VALUES(1,123,123);

INSERT INTO test_int2(f1,f2)
VALUES(123456,123456);

INSERT INTO test_int2(f1,f2,f3)
VALUES(123456,123456,123456);
mysql> SELECT * FROM test_int2;
+--------+--------+--------+
| f1     | f2     | f3     |
+--------+--------+--------+
|      1 |    123 |  00123 |
| 123456 | 123456 |   NULL |
| 123456 | 123456 | 123456 |
+--------+--------+--------+
3 rows in set (0.00 sec)

2.2.2 UNSIGNED

UNSIGNED: 無符號型別(非負),所有的整數型別都有一個可選的屬性UNSIGNED(無符號屬性),無符號整數型別的最小取值為0。所以,如果需要在MySQL資料庫中儲存非負整數值時,可以將整數型別設定為無符號型別。

int型別預設顯示寬度為int(11),無符號int型別預設顯示寬度為int(10)。

CREATE TABLE test_int3(
f1 INT UNSIGNED
);

mysql> desc test_int3;
+-------+------------------+------+-----+---------+-------+
| Field | Type             | Null | Key | Default | Extra |
+-------+------------------+------+-----+---------+-------+
| f1    | int(10) unsigned | YES  |     | NULL    |       |
+-------+------------------+------+-----+---------+-------+
1 row in set (0.00 sec)

2.2.3 ZEROFILL

ZEROFILL: 0填充,(如果某列是ZEROFILL,那麼MySQL會自動為當前列新增UNSIGNED屬性),如果指定了ZEROFILL只是表示不夠M位時,用0在左邊填充,如果超過M位,只要不超過資料儲存範圍即可。

原來,在 int(M) 中,M 的值跟 int(M) 所佔多少儲存空間並無任何關係。 int(3)、int(4)、int(8) 在磁碟上都是佔用 4 bytes 的儲存空間。也就是說,int(M),必須和UNSIGNED ZEROFILL一起使用才有意義。如果整數值超過M位,就按照實際位數儲存。只是無須再用字元 0 進行填充。

2.3 適用場景

TINYINT:一般用於列舉資料,比如系統設定取值範圍很小且固定的場景。

SMALLINT:可以用於較小範圍的統計資料,比如統計工廠的固定資產庫存數量等。

MEDIUMINT:用於較大整數的計算,比如車站每日的客流量等。

INT、INTEGER:取值範圍足夠大,一般情況下不用考慮超限問題,用得最多。比如商品編號。

BIGINT:只有當你處理特別巨大的整數時才會用到。比如雙十一的交易量、大型入口網站點選量、證券公司衍生產品持倉等。

2.4 如何選擇?

在評估用哪種整數型別的時候,你需要考慮儲存空間可靠性的平衡問題:一方 面,用佔用位元組數少的整數型別可以節省儲存空間;另一方面,要是為了節省儲存空間, 使用的整數型別取值範圍太小,一旦遇到超出取值範圍的情況,就可能引起系統錯誤,影響可靠性。

舉個例子,商品編號採用的資料型別是 INT。原因就在於,客戶門店中流通的商品種類較多,而且,每天都有舊商品下架,新商品上架,這樣不斷迭代,日積月累。

如果使用 SMALLINT 型別,雖然佔用位元組數比 INT 型別的整數少,但是卻不能保證資料不會超出範圍 65535。相反,使用 INT,就能確保有足夠大的取值範圍,不用擔心資料超出範圍影響可靠性的問題。

你要注意的是,在實際工作中,系統故障產生的成本遠遠超過增加幾個欄位儲存空間所產生的成本。因此,我建議你首先確保資料不會超過取值範圍,在這個前提之下,再去考慮如何節省儲存空間。

3. 浮點型別

3.1 型別介紹

浮點數和定點數型別的特點是可以處理小數,你可以把整數看成小數的一個特例。因此,浮點數和定點數的使用場景,比整數大多了。 MySQL支援的浮點數型別,分別是 FLOAT、DOUBLE、REAL。

  • FLOAT 表示單精度浮點數;
  • DOUBLE 表示雙精度浮點數;
  • REAL預設就是 DOUBLE。如果你把 SQL 模式設定為啟用“REAL_AS_FLOAT”,那 麼,MySQL 就認為 REAL 是 FLOAT。如果要啟用“REAL_AS_FLOAT”,可以通過以下 SQL 語句實現:

    SET sql_mode = “REAL_AS_FLOAT”;
    

問題1:FLOAT 和 DOUBLE 這兩種資料型別的區別是啥呢?

FLOAT 佔用位元組數少,取值範圍小;DOUBLE 佔用位元組數多,取值範圍也大。

問題2:為什麼浮點數型別的無符號數取值範圍,只相當於有符號數取值範圍的一半,也就是隻相當於有符號數取值範圍大於等於零的部分呢?

MySQL 儲存浮點數的格式為:符號(S)尾數(M)階碼(E)。因此,無論有沒有符號,MySQL 的浮點數都會儲存表示符號的部分。因此, 所謂的無符號數取值範圍,其實就是有符號數取值範圍大於等於零的部分。

3.2 資料精度說明

對於浮點型別,在MySQL中單精度值使用4個位元組,雙精度值使用8個位元組。

  • MySQL允許使用非標準語法(其他資料庫未必支援,因此如果涉及到資料遷移,則最好不要這麼用):FLOAT(M,D)DOUBLE(M,D)。這裡,M稱為精度,D稱為標度。(M,D)中 M=整數位+小數位,D=小數位。 D<=M<=255,0<=D<=30。

    例如,定義為FLOAT(5,2)的一個列可以顯示為-999.99-999.99。如果超過這個範圍會報錯。

  • FLOAT和DOUBLE型別在不指定(M,D)時,預設會按照實際的精度(由實際的硬體和作業系統決定)來顯示。

  • 說明:浮點型別,也可以加UNSIGNED,但是不會改變資料範圍,例如:FLOAT(3,2) UNSIGNED仍然只能表示0-9.99的範圍。

  • 不管是否顯式設定了精度(M,D),這裡MySQL的處理方案如下:

    • 如果儲存時,整數部分超出了範圍,MySQL就會報錯,不允許存這樣的值

    • 如果儲存時,小數點部分若超出範圍,就分以下情況:

      • 若四捨五入後,整數部分沒有超出範圍,則只警告,但能成功操作並四捨五入刪除多餘的小數位後儲存。例如在FLOAT(5,2)列內插入999.009,近似結果是999.01。
      • 若四捨五入後,整數部分超出範圍,則MySQL報錯,並拒絕處理。如FLOAT(5,2)列內插入999.995和-999.995都會報錯。
  • 從MySQL 8.0.17開始,FLOAT(M,D) 和DOUBLE(M,D)用法在官方文件中已經明確不推薦使用,將來可能被移除。另外,關於浮點型FLOAT和DOUBLE的UNSIGNED也不推薦使用了,將來也可能被移除。

  • 舉例

    CREATE TABLE test_double1(
    f1 FLOAT,
    f2 FLOAT(5,2),
    f3 DOUBLE,
    f4 DOUBLE(5,2)
    );
    
    DESC test_double1;
    
    INSERT INTO test_double1
    VALUES(123.456,123.456,123.4567,123.45);
    
    #Out of range value for column 'f2' at row 1
    INSERT INTO test_double1
    VALUES(123.456,1234.456,123.4567,123.45); 
    
    SELECT * FROM test_double1;
    

3.3 精度誤差說明

浮點數型別有個缺陷,就是不精準。下面我來重點解釋一下為什麼 MySQL 的浮點數不夠精準。比如,我們設計一個表,有f1這個欄位,插入值分別為0.47,0.44,0.19,我們期待的執行結果是:0.47 + 0.44 + 0.19 = 1.1。而使用sum之後查詢:

CREATE TABLE test_double2(
f1 DOUBLE
);

INSERT INTO test_double2
VALUES(0.47),(0.44),(0.19);
mysql> SELECT SUM(f1)
    -> FROM test_double2;
+--------------------+
| SUM(f1)            |
+--------------------+
| 1.0999999999999999 |
+--------------------+
1 row in set (0.00 sec)
mysql> SELECT SUM(f1) = 1.1,1.1 = 1.1
    -> FROM test_double2;
+---------------+-----------+
| SUM(f1) = 1.1 | 1.1 = 1.1 |
+---------------+-----------+
|             0 |         1 |
+---------------+-----------+
1 row in set (0.00 sec)

查詢結果是 1.0999999999999999。看到了嗎?雖然誤差很小,但確實有誤差。 你也可以嘗試把資料型別改成 FLOAT,然後執行求和查詢,得到的是, 1.0999999940395355。顯然,誤差更大了。

那麼,為什麼會存在這樣的誤差呢?問題還是出在 MySQL 對浮點型別資料的儲存方式上。

MySQL 用 4 個位元組儲存 FLOAT 型別資料,用 8 個位元組來儲存 DOUBLE 型別資料。無論哪個,都是採用二進位制的方式來進行儲存的。比如 9.625,用二進位制來表達,就是 1001.101,或者表達成 1.001101×2^3。如果尾數不是 0 或 5(比如 9.624),你就無法用一個二進位制數來精確表達。進而,就只好在取值允許的範圍內進行四捨五入。

在程式設計中,如果用到浮點數,要特別注意誤差問題,因為浮點數是不準確的,所以我們要避免使用“=”來判斷兩個數是否相等。同時,在一些對精確度要求較高的專案中,千萬不要使用浮點數,不然會導致結果錯誤,甚至是造成不可挽回的損失。那麼,MySQL 有沒有精準的資料型別呢?當然有,這就是定點數型別:DECIMAL

4. 定點數型別

4.1 型別介紹

  • MySQL中的定點數型別只有 DECIMAL 一種型別。

    資料型別 位元組數 含義
    DECIMAL(M,D),DEC,NUMERIC M+2位元組 有效範圍由M和D決定

    使用 DECIMAL(M,D) 的方式表示高精度小數。其中,M被稱為精度,D被稱為標度。0<=M<=65,0<=D<=30,D<M。例如,定義DECIMAL(5,2)的型別,表示該列取值範圍是-999.99~999.99。

  • DECIMAL(M,D)的最大取值範圍與DOUBLE型別一樣,但是有效的資料範圍是由M和D決定的。DECIMAL 的儲存空間並不是固定的,由精度值M決定,總共佔用的儲存空間為M+2個位元組。也就是說,在一些對精度要求不高的場景下,比起佔用同樣位元組長度的定點數,浮點數表達的數值範圍可以更大一些。

  • 定點數在MySQL內部是以字串的形式進行儲存,這就決定了它一定是精準的。

  • 當DECIMAL型別不指定精度和標度時,其預設為DECIMAL(10,0)。當資料的精度超出了定點數型別的精度範圍時,則MySQL同樣會進行四捨五入處理。

  • 浮點數 vs 定點數

    • 浮點數相對於定點數的優點是在長度一定的情況下,浮點型別取值範圍大,但是不精準,適用於需要取值範圍大,又可以容忍微小誤差的科學計算場景(比如計算化學、分子建模、流體動力學等)
    • 定點數型別取值範圍相對小,但是精準,沒有誤差,適合於對精度要求極高的場景 (比如涉及金額計算的場景)
  • 舉例

    CREATE TABLE test_decimal1(
    f1 DECIMAL,
    f2 DECIMAL(5,2)
    );
    
    DESC test_decimal1;
    
    INSERT INTO test_decimal1(f1,f2)
    VALUES(123.123,123.456);
    
    #Out of range value for column 'f2' at row 1
    INSERT INTO test_decimal1(f2)
    VALUES(1234.34);
    
    mysql> SELECT * FROM test_decimal1;
    +------+--------+
    | f1   | f2     |
    +------+--------+
    |  123 | 123.46 |
    +------+--------+
    1 row in set (0.00 sec)
    
  • 舉例

    我們執行下面的語句,把test_double2表中欄位“f1”的資料型別修改為 DECIMAL(5,2):

    ALTER TABLE test_double2
    MODIFY f1 DECIMAL(5,2);
    

    然後,我們再一次執行求和語句:

    mysql> SELECT SUM(f1)
        -> FROM test_double2;
    +---------+
    | SUM(f1) |
    +---------+
    |    1.10 |
    +---------+
    1 row in set (0.00 sec)
    
    mysql> SELECT SUM(f1) = 1.1
        -> FROM test_double2;
    +---------------+
    | SUM(f1) = 1.1 |
    +---------------+
    |             1 |
    +---------------+
    1 row in set (0.00 sec)
    

4.2 開發中經驗

“由於 DECIMAL 資料型別的精準性,在我們的專案中,除了極少數(比如商品編號)用到整數型別外,其他的數值都用的是 DECIMAL,原因就是這個專案所處的零售行業,要求精準,一分錢也不能差。 ” ——來自某專案經理

5. 位型別:BIT

BIT型別中儲存的是二進位制值,類似010110。

二進位制字串型別 長度 長度範圍 佔用空間
BIT(M) M 1 <= M <= 64 約為(M + 7)/8個位元組

BIT型別,如果沒有指定(M),預設是1位。這個1位,表示只能存1位的二進位制值。這裡(M)是表示二進位制的位數,位數最小值為1,最大值為64。

CREATE TABLE test_bit1(
f1 BIT,
f2 BIT(5),
f3 BIT(64)
);

INSERT INTO test_bit1(f1)
VALUES(1);

#Data too long for column 'f1' at row 1
INSERT INTO test_bit1(f1)
VALUES(2);

INSERT INTO test_bit1(f2)
VALUES(23);

注意:在向BIT型別的欄位中插入資料時,一定要確保插入的資料在BIT型別支援的範圍內。

使用SELECT命令查詢位欄位時,可以用BIN()HEX()函式進行讀取。

mysql> SELECT * FROM test_bit1;
+------------+------------+------------+
| f1         | f2         | f3         |
+------------+------------+------------+
| 0x01       | NULL       | NULL       |
| NULL       | 0x17       | NULL       |
+------------+------------+------------+
2 rows in set (0.00 sec)
mysql> SELECT BIN(f2),HEX(f2)
    -> FROM test_bit1;
+---------+---------+
| BIN(f2) | HEX(f2) |
+---------+---------+
| NULL    | NULL    |
| 10111   | 17      |
+---------+---------+
2 rows in set (0.00 sec)
mysql> SELECT f2 + 0
    -> FROM test_bit1;
+--------+
| f2 + 0 |
+--------+
|   NULL |
|     23 |
+--------+
2 rows in set (0.00 sec)

可以看到,使用b+0查詢資料時,可以直接查詢出儲存的十進位制資料的值。

6. 日期與時間型別

日期與時間是重要的資訊,在我們的系統中,幾乎所有的資料表都用得到。原因是客戶需要知道資料的時間標籤,從而進行資料查詢、統計和處理。

MySQL有多種表示日期和時間的資料型別,不同的版本可能有所差異,MySQL8.0版本支援的日期和時間型別主要有:YEAR型別、TIME型別、DATE型別、DATETIME型別和TIMESTAMP型別。

  • YEAR型別通常用來表示年
  • DATE型別通常用來表示年、月、日
  • TIME型別通常用來表示時、分、秒
  • DATETIME型別通常用來表示年、月、日、時、分、秒
  • TIMESTAMP型別通常用來表示帶時區的年、月、日、時、分、秒
型別 名稱 位元組 日期格式 最小值 最大值
YEAR 1 YYYY或YY 1901 2155
TIME 時間 3 HH:MM:SS -838:59:59 838:59:59
DATE 日期 3 YYYY-MM-DD 1000-01-01 9999-12-03
DATETIME 日期時間 8 YYYY-MM-DD HH:MM:SS 1000-01-01 00:00:00 9999-12-31 23:59:59
TIMESTAMP 日期時間 4 YYYY-MM-DD HH:MM:SS 1970-01-01 00:00:00 UTC 2038-01-19 03:14:07UTC

可以看到,不同資料型別表示的時間內容不同、取值範圍不同,而且佔用的位元組數也不一樣,你要根據實際需要靈活選取。

為什麼時間型別 TIME 的取值範圍不是 -23:59:59~23:59:59 呢?原因是 MySQL 設計的 TIME 型別,不光表示一天之內的時間,而且可以用來表示一個時間間隔,這個時間間隔可以超過 24 小時。

6.1 YEAR型別

YEAR型別用來表示年份,在所有的日期時間型別中所佔用的儲存空間最小,只需要1個位元組的儲存空間。

在MySQL中,YEAR有以下幾種儲存格式:

  • 以4位字串或數字格式表示YEAR型別,其格式為YYYY,最小值為1901,最大值為2155。
  • 以2位字串格式表示YEAR型別,最小值為00,最大值為99。
    • 當取值為01到69時,表示2001到2069;
    • 當取值為70到99時,表示1970到1999;
    • 當取值整數的0或00新增的話,那麼是0000年;
    • 當取值是日期/字串的'0'新增的話,是2000年。

從MySQL5.5.27開始,2位格式的YEAR已經不推薦使用。YEAR預設格式就是“YYYY”,沒必要寫成YEAR(4),從MySQL 8.0.19開始,不推薦使用指定顯示寬度的YEAR(4)資料型別。

CREATE TABLE test_year(
f1 YEAR,
f2 YEAR(4)
);
mysql> DESC test_year;
+-------+---------+------+-----+---------+-------+
| Field | Type    | Null | Key | Default | Extra |
+-------+---------+------+-----+---------+-------+
| f1    | year(4) | YES  |     | NULL    |       |
| f2    | year(4) | YES  |     | NULL    |       |
+-------+---------+------+-----+---------+-------+
2 rows in set (0.00 sec)
INSERT INTO test_year
VALUES('2020','2021');

mysql> SELECT * FROM test_year;
+------+------+
| f1   | f2   |
+------+------+
| 2020 | 2021 |
+------+------+
1 rows in set (0.00 sec)
INSERT INTO test_year
VALUES('45','71');

INSERT INTO test_year
VALUES(0,'0');

mysql> SELECT * FROM test_year;
+------+------+
| f1   | f2   |
+------+------+
| 2020 | 2021 |
| 2045 | 1971 |
| 0000 | 2000 |
+------+------+
3 rows in set (0.00 sec)

6.2 DATE型別

DATE型別表示日期,沒有時間部分,格式為YYYY-MM-DD,其中,YYYY表示年份,MM表示月份,DD表示日期。需要3個位元組的儲存空間。在向DATE型別的欄位插入資料時,同樣需要滿足一定的格式條件。

  • YYYY-MM-DD格式或者YYYYMMDD格式表示的字串日期,其最小取值為1000-01-01,最大取值為9999-12-03。YYYYMMDD格式會被轉化為YYYY-MM-DD格式。
  • YY-MM-DD格式或者YYMMDD格式表示的字串日期,此格式中,年份為兩位數值或字串滿足YEAR型別的格式條件為:當年份取值為00到69時,會被轉化為2000到2069;當年份取值為70到99時,會被轉化為1970到1999。
  • 使用CURRENT_DATE()或者NOW()函式,會插入當前系統的日期。

舉例:

建立資料表,表中只包含一個DATE型別的欄位f1。

CREATE TABLE test_date1(
f1 DATE
);
Query OK, 0 rows affected (0.13 sec)

插入資料:

INSERT INTO test_date1
VALUES ('2020-10-01'), ('20201001'),(20201001);

INSERT INTO test_date1
VALUES ('00-01-01'), ('000101'), ('69-10-01'), ('691001'), ('70-01-01'), ('700101'), ('99-01-01'), ('990101');

INSERT INTO test_date1
VALUES (000301), (690301), (700301), (990301); 

INSERT INTO test_date1
VALUES (CURRENT_DATE()), (NOW());

SELECT *
FROM test_date1;

6.3 TIME型別

TIME型別用來表示時間,不包含日期部分。在MySQL中,需要3個位元組的儲存空間來儲存TIME型別的資料,可以使用“HH:MM:SS”格式來表示TIME型別,其中,HH表示小時,MM表示分鐘,SS表示秒。

在MySQL中,向TIME型別的欄位插入資料時,也可以使用幾種不同的格式。
(1)可以使用帶有冒號的字串,比如'D HH:MM:SS'、'HH:MM:SS'、'HH:MM'、'D HH:MM'、'D HH'或'SS'格式,都能被正確地插入TIME型別的欄位中。其中D表示天,其最小值為0,最大值為34。如果使用帶有D格式的字串插入TIME型別的欄位時,D會被轉化為小時,計算格式為D*24+HH。當使用帶有冒號並且不帶D的字串表示時間時,表示當天的時間,比如12:10表示12:10:00,而不是00:12:10。
(2)可以使用不帶有冒號的字串或者數字,格式為'HHMMSS'或者HHMMSS。如果插入一個不合法的字串或者數字,MySQL在儲存資料時,會將其自動轉化為00:00:00進行儲存。比如1210,MySQL會將最右邊的兩位解析成秒,表示00:12:10,而不是12:10:00。
(3)使用CURRENT_TIME()或者NOW(),會插入當前系統的時間。

舉例:

建立資料表,表中包含一個TIME型別的欄位f1。

CREATE TABLE test_time1(
f1 TIME
);
Query OK, 0 rows affected (0.02 sec)
INSERT INTO test_time1
VALUES('2 12:30:29'), ('12:35:29'), ('12:40'), ('2 12:40'),('1 05'), ('45');

INSERT INTO test_time1
VALUES ('123520'), (124011),(1210);

INSERT INTO test_time1
VALUES (NOW()), (CURRENT_TIME());

SELECT * FROM test_time1;

6.4 DATETIME型別

DATETIME型別在所有的日期時間型別中佔用的儲存空間最大,總共需要8個位元組的儲存空間。在格式上為DATE型別和TIME型別的組合,可以表示為YYYY-MM-DD HH:MM:SS,其中YYYY表示年份,MM表示月份,DD表示日期,HH表示小時,MM表示分鐘,SS表示秒。

在向DATETIME型別的欄位插入資料時,同樣需要滿足一定的格式條件。

  • YYYY-MM-DD HH:MM:SS格式或者YYYYMMDDHHMMSS格式的字串插入DATETIME型別的欄位時,最小值為1000-01-01 00:00:00,最大值為9999-12-03 23:59:59。
    • 以YYYYMMDDHHMMSS格式的數字插入DATETIME型別的欄位時,會被轉化為YYYY-MM-DD HH:MM:SS格式。
  • YY-MM-DD HH:MM:SS格式或者YYMMDDHHMMSS格式的字串插入DATETIME型別的欄位時,兩位數的年份規則符合YEAR型別的規則,00到69表示2000到2069;70到99表示1970到1999。
  • 使用函式CURRENT_TIMESTAMP()NOW(),可以向DATETIME型別的欄位插入系統的當前日期和時間。

舉例:

建立資料表,表中包含一個DATETIME型別的欄位dt。

CREATE TABLE test_datetime1(
dt DATETIME
);
Query OK, 0 rows affected (0.02 sec)

插入資料:

INSERT INTO test_datetime1
VALUES ('2021-01-01 06:50:30'), ('20210101065030');

INSERT INTO test_datetime1
VALUES ('99-01-01 00:00:00'), ('990101000000'), ('20-01-01 00:00:00'), ('200101000000');

INSERT INTO test_datetime1
VALUES (20200101000000), (200101000000), (19990101000000), (990101000000);
 
INSERT INTO test_datetime1
VALUES (CURRENT_TIMESTAMP()), (NOW());

6.5 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”之間的時間。其中,UTC表示世界統一時間,也叫作世界標準時間。

  • 儲存資料的時候需要對當前時間所在的時區進行轉換,查詢資料的時候再將時間轉換回當前的時區。因此,使用TIMESTAMP儲存的同一個時間值,在不同的時區查詢時會顯示不同的時間。

向TIMESTAMP型別的欄位插入資料時,當插入的資料格式滿足YY-MM-DD HH:MM:SS和YYMMDDHHMMSS時,兩位數值的年份同樣符合YEAR型別的規則條件,只不過表示的時間範圍要小很多。

如果向TIMESTAMP型別的欄位插入的時間超出了TIMESTAMP型別的範圍,則MySQL會丟擲錯誤資訊。

舉例:

建立資料表,表中包含一個TIMESTAMP型別的欄位ts。

CREATE TABLE test_timestamp1(
ts TIMESTAMP
);

插入資料:

INSERT INTO test_timestamp1
VALUES ('1999-01-01 03:04:50'), ('19990101030405'), ('99-01-01 03:04:05'), ('990101030405');

INSERT INTO test_timestamp1
VALUES ('2020@01@01@00@00@00'), ('20@01@01@00@00@00');

INSERT INTO test_timestamp1
VALUES (CURRENT_TIMESTAMP()), (NOW());

#Incorrect datetime value
INSERT INTO test_timestamp1
VALUES ('2038-01-20 03:14:07');

TIMESTAMP和DATETIME的區別:

  • TIMESTAMP儲存空間比較小,表示的日期時間範圍也比較小

  • 底層儲存方式不同,TIMESTAMP底層儲存的是毫秒值,距離1970-1-1 0:0:0 0毫秒的毫秒值。

  • 兩個日期比較大小或日期計算時,TIMESTAMP更方便、更快。

  • TIMESTAMP和時區有關。TIMESTAMP會根據使用者的時區不同,顯示不同的結果。而DATETIME則只能反映出插入時當地的時區,其他時區的人檢視資料必然會有誤差的。

    CREATE TABLE temp_time(
    d1 DATETIME,
    d2 TIMESTAMP
    );
    
    INSERT INTO temp_time VALUES('2021-9-2 14:45:52','2021-9-2 14:45:52');
    
    INSERT INTO temp_time VALUES(NOW(),NOW());
    
    mysql> SELECT * FROM temp_time;
    +---------------------+---------------------+
    | d1                  | d2                  |
    +---------------------+---------------------+
    | 2021-09-02 14:45:52 | 2021-09-02 14:45:52 |
    | 2021-11-03 17:38:17 | 2021-11-03 17:38:17 |
    +---------------------+---------------------+
    2 rows in set (0.00 sec)
    
    #修改當前的時區
    SET time_zone = '+9:00';
    
    mysql> SELECT * FROM temp_time;
    +---------------------+---------------------+
    | d1                  | d2                  |
    +---------------------+---------------------+
    | 2021-09-02 14:45:52 | 2021-09-02 15:45:52 |
    | 2021-11-03 17:38:17 | 2021-11-03 18:38:17 |
    +---------------------+---------------------+
    2 rows in set (0.00 sec)
    

6.6 開發中經驗

用得最多的日期時間型別,就是 DATETIME。雖然 MySQL 也支援 YEAR(年)、 TIME(時間)、DATE(日期),以及 TIMESTAMP 型別,但是在實際專案中,儘量用 DATETIME 型別。因為這個資料型別包括了完整的日期和時間資訊,取值範圍也最大,使用起來比較方便。畢竟,如果日期時間資訊分散在好幾個欄位,很不容易記,而且查詢的時候,SQL 語句也會更加複雜。

此外,一般存註冊時間、商品釋出時間等,不建議使用DATETIME儲存,而是使用時間戳,因為DATETIME雖然直觀,但不便於計算。

mysql> SELECT UNIX_TIMESTAMP();
+------------------+
| UNIX_TIMESTAMP() |
+------------------+
|       1635932762 |
+------------------+
1 row in set (0.00 sec)

7. 文字字串型別

在實際的專案中,我們還經常遇到一種資料,就是字串資料。

MySQL中,文字字串總體上分為CHARVARCHARTINYTEXTTEXTMEDIUMTEXTLONGTEXTENUMSET等型別。

7.1 CHAR與VARCHAR型別

CHAR和VARCHAR型別都可以儲存比較短的字串。

字串(文字)型別 特點 長度 長度範圍 佔用的儲存空間
CHAR(M) 固定長度 M 0 <= M <= 255 M個位元組
VARCHAR(M) 可變長度 M 0 <= M <= 65535 (實際長度 + 1) 個位元組

CHAR型別:

  • CHAR(M) 型別一般需要預先定義字串長度。如果不指定(M),則表示長度預設是1個字元。
  • 如果儲存時,資料的實際長度比CHAR型別宣告的長度小,則會在右側填充空格以達到指定的長度。當MySQL檢索CHAR型別的資料時,CHAR型別的欄位會去除尾部的空格。
  • 定義CHAR型別欄位時,宣告的欄位長度即為CHAR型別欄位所佔的儲存空間的位元組數。
CREATE TABLE test_char1(
c1 CHAR,
c2 CHAR(5)
);

DESC test_char1;
INSERT INTO test_char1
VALUES('a','Tom');

SELECT c1,CONCAT(c2,'***') FROM test_char1;
INSERT INTO test_char1(c2)
VALUES('a  ');

SELECT CHAR_LENGTH(c2)
FROM test_char1;

VARCHAR型別:

  • VARCHAR(M) 定義時,必須指定長度M,否則報錯。
  • MySQL4.0版本以下,varchar(20):指的是20位元組,如果存放UTF8漢字時,只能存6個(每個漢字3位元組) ;MySQL5.0版本以上,varchar(20):指的是20字元。
  • 檢索VARCHAR型別的欄位資料時,會保留資料尾部的空格。VARCHAR型別的欄位所佔用的儲存空間為字串實際長度加1個位元組。
CREATE TABLE test_varchar1(
NAME VARCHAR  #錯誤
);
#Column length too big for column 'NAME' (max = 21845);
CREATE TABLE test_varchar2(
NAME VARCHAR(65535)  #錯誤
);
CREATE TABLE test_varchar3(
NAME VARCHAR(5)
);

INSERT INTO test_varchar3
VALUES('尚矽谷'),('尚矽谷教育');

#Data too long for column 'NAME' at row 1
INSERT INTO test_varchar3
VALUES('尚矽谷IT教育');

哪些情況使用 CHAR 或 VARCHAR 更好

型別 特點 空間上 時間上 適用場景
CHAR(M) 固定長度 浪費儲存空間 效率高 儲存不大,速度要求高
VARCHAR(M) 可變長度 節省儲存空間 效率低 非CHAR的情況

情況1:儲存很短的資訊。比如門牌號碼101,201……這樣很短的資訊應該用char,因為varchar還要佔個byte用於儲存資訊長度,本來打算節約儲存的,結果得不償失。

情況2:固定長度的。比如使用uuid作為主鍵,那用char應該更合適。因為他固定長度,varchar動態根據長度的特性就消失了,而且還要佔個長度資訊。

情況3:十分頻繁改變的column。因為varchar每次儲存都要有額外的計算,得到長度等工作,如果一個非常頻繁改變的,那就要有很多的精力用於計算,而這些對於char來說是不需要的。

情況4:具體儲存引擎中的情況:

  • MyISAM 資料儲存引擎和資料列:MyISAM資料表,最好使用固定長度(CHAR)的資料列代替可變長度(VARCHAR)的資料列。這樣使得整個表靜態化,從而使資料檢索更快,用空間換時間。

  • MEMORY 儲存引擎和資料列:MEMORY資料表目前都使用固定長度的資料行儲存,因此無論使用CHAR或VARCHAR列都沒有關係,兩者都是作為CHAR型別處理的。

  • InnoDB儲存引擎,建議使用VARCHAR型別。因為對於InnoDB資料表,內部的行儲存格式並沒有區分固定長度和可變長度列(所有資料行都使用指向資料列值的頭指標),而且主要影響效能的因素是資料行使用的儲存總量,由於char平均佔用的空間多於varchar,所以除了簡短並且固定長度的,其他考慮varchar。這樣節省空間,對磁碟I/O和資料儲存總量比較好。

7.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<= 4294967295(相當於4GB) L + 4 個位元組

由於實際儲存的長度不確定,MySQL 不允許 TEXT 型別的欄位做主鍵。遇到這種情況,你只能採用 CHAR(M),或者 VARCHAR(M)。

舉例:

建立資料表:

CREATE TABLE test_text(
tx TEXT
);
INSERT INTO test_text
VALUES('atguigu   ');

SELECT CHAR_LENGTH(tx)
FROM test_text; #10

說明在儲存和查詢資料時,並沒有刪除TEXT型別的資料尾部的空格。

開發中經驗:

TEXT文字型別,可以存比較大的文字段,搜尋速度稍慢,因此如果不是特別大的內容,建議使用CHAR,VARCHAR來代替。還有TEXT型別不用加預設值,加了也沒用。而且text和blob型別的資料刪除後容易導致“空洞”,使得檔案碎片比較多,所以頻繁使用的表不建議包含TEXT型別欄位,建議單獨分出去,單獨用一個表。

8. ENUM型別

ENUM型別也叫作列舉型別,ENUM型別的取值範圍需要在定義欄位時進行指定。設定欄位值時,ENUM型別只允許從成員中選取單個值,不能一次選取多個值。

其所需要的儲存空間由定義ENUM型別時指定的成員個數決定。

文字字串型別 長度 長度範圍 佔用的儲存空間
ENUM L 1 <= L <= 65535 1或2個位元組
  • 當ENUM型別包含1~255個成員時,需要1個位元組的儲存空間;

  • 當ENUM型別包含256~65535個成員時,需要2個位元組的儲存空間。

  • ENUM型別的成員個數的上限為65535個。

舉例:

建立表如下:

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);

9. SET型別

SET表示一個字串物件,可以包含0個或多個成員,但成員個數的上限為64。設定欄位值時,可以取取值範圍內的 0 個或多個值。

當SET型別包含的成員個數不同時,其所佔用的儲存空間也是不同的,具體如下:

成員個數範圍(L表示實際成員個數) 佔用的儲存空間
1 <= L <= 8 1個位元組
9 <= L <= 16 2個位元組
17 <= L <= 24 3個位元組
25 <= L <= 32 4個位元組
33 <= L <= 64 8個位元組

SET型別在儲存資料時成員個數越多,其佔用的儲存空間越大。注意:SET型別在選取成員時,可以一次選擇多個成員,這一點與ENUM型別不同。

舉例:

建立表:

CREATE TABLE test_set(
s SET ('A', 'B', 'C')
);

向表中插入資料:

INSERT INTO test_set (s) VALUES ('A'), ('A,B');

#插入重複的SET型別成員時,MySQL會自動刪除重複的成員
INSERT INTO test_set (s) VALUES ('A,B,C,A');

#向SET型別的欄位插入SET成員中不存在的值時,MySQL會丟擲錯誤。
INSERT INTO test_set (s) VALUES ('A,B,C,D');

SELECT *
FROM test_set;

舉例:

CREATE TABLE temp_mul(
gender ENUM('男','女'),
hobby SET('吃飯','睡覺','打豆豆','寫程式碼')
);
INSERT INTO temp_mul VALUES('男','睡覺,打豆豆'); #成功

# Data truncated for column 'gender' at row 1
INSERT INTO temp_mul VALUES('男,女','睡覺,寫程式碼'); #失敗

# Data truncated for column 'gender' at row 1
INSERT INTO temp_mul VALUES('妖','睡覺,寫程式碼');#失敗


INSERT INTO temp_mul VALUES('男','睡覺,寫程式碼,吃飯'); #成功

10. 二進位制字串型別

MySQL中的二進位制字串型別主要儲存一些二進位制資料,比如可以儲存圖片、音訊和視訊等二進位制資料。

MySQL中支援的二進位制字串型別主要包括BINARY、VARBINARY、TINYBLOB、BLOB、MEDIUMBLOB 和 LONGBLOB型別。

BINARY與VARBINARY型別

BINARY和VARBINARY類似於CHAR和VARCHAR,只是它們儲存的是二進位制字串。

BINARY (M)為固定長度的二進位制字串,M表示最多能儲存的位元組數,取值範圍是0~255個字元。如果未指定(M),表示只能儲存1個位元組。例如BINARY (8),表示最多能儲存8個位元組,如果欄位值不足(M)個位元組,將在右邊填充'\0'以補齊指定長度。

VARBINARY (M)為可變長度的二進位制字串,M表示最多能儲存的位元組數,總位元組數不能超過行的位元組長度限制65535,另外還要考慮額外位元組開銷,VARBINARY型別的資料除了儲存資料本身外,還需要1或2個位元組來儲存資料的位元組數。VARBINARY型別必須指定(M),否則報錯。

二進位制字串型別 特點 值的長度 佔用空間
BINARY(M) 固定長度 M (0 <= M <= 255) M個位元組
VARBINARY(M) 可變長度 M(0 <= M <= 65535) M+1個位元組

舉例:

建立表:

CREATE TABLE test_binary1(
f1 BINARY,
f2 BINARY(3),
# f3 VARBINARY,
f4 VARBINARY(10)
);

新增資料:

INSERT INTO test_binary1(f1,f2)
VALUES('a','a');

INSERT INTO test_binary1(f1,f2)
VALUES('尚','尚');#失敗
INSERT INTO test_binary1(f2,f4)
VALUES('ab','ab');

mysql> SELECT LENGTH(f2),LENGTH(f4)
    -> FROM test_binary1;
+------------+------------+
| LENGTH(f2) | LENGTH(f4) |
+------------+------------+
|          3 |       NULL |
|          3 |          2 |
+------------+------------+
2 rows in set (0.00 sec)

BLOB型別

BLOB是一個二進位制大物件,可以容納可變數量的資料。

MySQL中的BLOB型別包括TINYBLOB、BLOB、MEDIUMBLOB和LONGBLOB 4種類型,它們可容納值的最大長度不同。可以儲存一個二進位制的大物件,比如圖片音訊視訊等。

需要注意的是,在實際工作中,往往不會在MySQL資料庫中使用BLOB型別儲存大物件資料,通常會將圖片、音訊和視訊檔案儲存到伺服器的磁碟上,並將圖片、音訊和視訊的訪問路徑儲存到MySQL中。

二進位制字串型別 值的長度 長度範圍 佔用空間
TINYBLOB L 0 <= L <= 255 L + 1 個位元組
BLOB L 0 <= L <= 65535(相當於64KB) L + 2 個位元組
MEDIUMBLOB L 0 <= L <= 16777215 (相當於16MB) L + 3 個位元組
LONGBLOB L 0 <= L <= 4294967295(相當於4GB) L + 4 個位元組

舉例:

CREATE TABLE test_blob1(
id INT,
img MEDIUMBLOB
);

TEXT和BLOB的使用注意事項:

在使用text和blob欄位型別時要注意以下幾點,以便更好的發揮資料庫的效能。

① BLOB和TEXT值也會引起自己的一些問題,特別是執行了大量的刪除或更新操作的時候。刪除這種值會在資料表中留下很大的"空洞",以後填入這些"空洞"的記錄可能長度不同。為了提高效能,建議定期使用 OPTIMIZE TABLE 功能對這類表進行碎片整理

② 如果需要對大文字欄位進行模糊查詢,MySQL 提供了字首索引。但是仍然要在不必要的時候避免檢索大型的BLOB或TEXT值。例如,SELECT * 查詢就不是很好的想法,除非你能夠確定作為約束條件的WHERE子句只會找到所需要的資料行。否則,你可能毫無目的地在網路上傳輸大量的值。

③ 把BLOB或TEXT列分離到單獨的表中。在某些環境中,如果把這些資料列移動到第二張資料表中,可以讓你把原資料表中的資料列轉換為固定長度的資料行格式,那麼它就是有意義的。這會減少主表中的碎片,使你得到固定長度資料行的效能優勢。它還使你在主資料表上執行 SELECT * 查詢的時候不會通過網路傳輸大量的BLOB或TEXT值。

11. JSON 型別

JSON(JavaScript Object Notation)是一種輕量級的資料交換格式。簡潔和清晰的層次結構使得 JSON 成為理想的資料交換語言。它易於人閱讀和編寫,同時也易於機器解析和生成,並有效地提升網路傳輸效率。JSON 可以將 JavaScript 物件中表示的一組資料轉換為字串,然後就可以在網路或者程式之間輕鬆地傳遞這個字串,並在需要的時候將它還原為各程式語言所支援的資料格式。

在MySQL 5.7中,就已經支援JSON資料型別。在MySQL 8.x版本中,JSON型別提供了可以進行自動驗證的JSON文件和優化的儲存結構,使得在MySQL中儲存和讀取JSON型別的資料更加方便和高效。
建立資料表,表中包含一個JSON型別的欄位 js 。

CREATE TABLE test_json(
js json

);

向表中插入JSON資料。

INSERT INTO test_json (js) 
VALUES ('{"name":"songhk", "age":18, "address":{"province":"beijing", "city":"beijing"}}');

查詢t19表中的資料。

mysql> SELECT *
    -> FROM test_json;

當需要檢索JSON型別的欄位中資料的某個具體值時,可以使用“->”和“->>”符號。

mysql> SELECT js -> '$.name' AS NAME,js -> '$.age' AS age ,js -> '$.address.province' AS province, js -> '$.address.city' AS city
    -> FROM test_json;
+----------+------+-----------+-----------+
| NAME     | age  | province  | city      |
+----------+------+-----------+-----------+
| "songhk" | 18   | "beijing" | "beijing" |
+----------+------+-----------+-----------+
1 row in set (0.00 sec)

通過“->”和“->>”符號,從JSON欄位中正確查詢出了指定的JSON資料的值。

12. 空間型別

MySQL 空間型別擴充套件支援地理特徵的生成、儲存和分析。這裡的地理特徵表示世界上具有位置的任何東西,可以是一個實體,例如一座山;可以是空間,例如一座辦公樓;也可以是一個可定義的位置,例如一個十字路口等等。MySQL中使用Geometry(幾何)來表示所有地理特徵。Geometry指一個點或點的集合,代表世界上任何具有位置的事物。

MySQL的空間資料型別(Spatial Data Type)對應於OpenGIS類,包括單值型別:GEOMETRY、POINT、LINESTRING、POLYGON以及集合型別:MULTIPOINT、MULTILINESTRING、MULTIPOLYGON、GEOMETRYCOLLECTION 。

  • Geometry是所有空間集合型別的基類,其他型別如POINT、LINESTRING、POLYGON都是Geometry的子類。
    • Point,顧名思義就是點,有一個座標值。例如POINT(121.213342 31.234532),POINT(30 10),座標值支援DECIMAL型別,經度(longitude)在前,維度(latitude)在後,用空格分隔。
    • LineString,線,由一系列點連線而成。如果線從頭至尾沒有交叉,那就是簡單的(simple);如果起點和終點重疊,那就是封閉的(closed)。例如LINESTRING(30 10,10 30,40 40),點與點之間用逗號分隔,一個點中的經緯度用空格分隔,與POINT格式一致。
    • Polygon,多邊形。可以是一個實心平面形,即沒有內部邊界,也可以有空洞,類似鈕釦。最簡單的就是隻有一個外邊界的情況,例如POLYGON((0 0,10 0,10 10, 0 10))。

下面展示幾種常見的幾何圖形元素:

  • MultiPoint、MultiLineString、MultiPolygon、GeometryCollection 這4種類型都是集合類,是多個Point、LineString或Polygon組合而成。

下面展示的是多個同類或異類幾何圖形元素的組合:

13. 小結及選擇建議

在定義資料型別時,如果確定是整數,就用 INT; 如果是小數,一定用定點數型別 DECIMAL(M,D); 如果是日期與時間,就用 DATETIME

這樣做的好處是,首先確保你的系統不會因為資料型別定義出錯。不過,凡事都是有兩面的,可靠性好,並不意味著高效。比如,TEXT 雖然使用方便,但是效率不如 CHAR(M) 和 VARCHAR(M)。

關於字串的選擇,建議參考如下阿里巴巴的《Java開發手冊》規範:

阿里巴巴《Java開發手冊》之MySQL資料庫:

  • 任何欄位如果為非負數,必須是 UNSIGNED
  • 強制】小數型別為 DECIMAL,禁止使用 FLOAT 和 DOUBLE。
    • 說明:在儲存的時候,FLOAT 和 DOUBLE 都存在精度損失的問題,很可能在比較值的時候,得到不正確的結果。如果儲存的資料範圍超過 DECIMAL 的範圍,建議將資料拆成整數和小數並分開儲存。
  • 強制】如果儲存的字串長度幾乎相等,使用 CHAR 定長字串型別。
  • 強制】VARCHAR 是可變長字串,不預先分配儲存空間,長度不要超過 5000。如果儲存長度大於此值,定義欄位型別為 TEXT,獨立出來一張表,用主鍵來對應,避免影響其它欄位索引效率。

本文來自部落格園,作者:微笑帶你去,轉載請註明原文連結:https://www.cnblogs.com/wxdnq/p/15602193.html