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

第12章_MySQL資料型別精講

第12章_MySQL資料型別精講

講師:尚矽谷-宋紅康(江湖人稱:康師傅)

官網:http://www.atguigu.com


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,獨立出來一張表,用主鍵來對應,避免影響其它欄位索引效率。