1. 程式人生 > 實用技巧 >8. 選擇合適的資料型別

8. 選擇合適的資料型別

8.1 CHAR與VARCHAR

​ CHAR 和 VARCHAR 型別類似,都用來儲存字串,但它們儲存和檢索的方式不同。CHAR 屬於固定長度的字元型別,而 VARCHAR 屬於可變長度的字元型別。當char定義一定寬度的格式時,資料末尾的空格會被處理掉。char是固定長度的,處理速度比varchar塊,但缺點是浪費空間。

char和varchar如何選擇?

在 MySQL 中,不同的儲存引擎對 CHAR 和 VARCHAR 的使用原則有所不同,這裡簡單概括如下。

  • MyISAM 儲存引擎:建議使用固定長度的資料列代替可變長度的資料列。
  • MEMORY 儲存引擎:目前都使用固定長度的資料行儲存,因此無論使用 CHAR 或VARCHAR 列都沒有關係。兩者都是作為 CHAR 型別處理。
  • InnoDB 儲存引擎:建議使用 VARCHAR 型別。對於 InnoDB 資料表,內部的行儲存格式沒有區分固定長度和可變長度列(所有資料行都使用指向資料列值的頭指標),因此在本質上,使用固定長度的 CHAR 列不一定比使用可變長度 VARCHAR 列效能要好。因而,主要的效能因素是資料行使用的儲存總量。由於 CHAR 平均佔用的空間多於 VARCHAR,因此使用 VARCHAR 來最小化需要處理的資料行的儲存總量和磁碟 I/O 是比較好的。

8.2 TEXT與BLOB

​ char或者varchar適用於儲存少量字串,如果儲存較大文字是,通常會選擇使用TEXT和BLOB。

BLOB:用來儲存二進位制資料,比如照片。

TEXT:只能儲存字元資料,比如一篇文章和日記。

TEXT 和 BLOB 中又分別包括TEXT、MEDIUMTEXT、LONGTEXT 和 BLOB、MEDIUMBLOB、LONGBLOB3 種不同的型別。

(1)BLOB 和 TEXT 值會引起一些效能問題,特別是在執行了大量的刪除操作時。 刪除操作會在資料表中留下很大的“空洞”,以後填入這些“空洞”的記錄在插入的效能上會有影響。為了提高效能,建議定期使用 OPTIMIZE TABLE 功能對這類表進行碎片整理,避免因為“空洞”導致效能問題。

(2)可以使用合成的(Synthetic)索引提高大文字欄位(BLOB 或 TEXT)的查詢效能

簡單來說,合成索引就是根據大文字欄位的內容建立一個雜湊值,並把這個值儲存在單獨的資料列中,接下來就可以通過檢索雜湊值找到資料行了。但是,要注意這種技術只能用於精確匹配的查詢(雜湊值對於類似<或>=等範圍搜尋操作符是沒有用處的)。

mysql>  create table t (id varchar(100),context  blob,hash_value varchar(40)); 
Query OK, 0 rows affected (0.02 sec)

mysql> insert into t values(1,repeat('beijing',2),md5(context));
Query OK, 1 row affected (0.01 sec)

mysql>  insert into t values(2,repeat('beijing',2),md5(context));
Query OK, 1 row affected (0.01 sec)

mysql> insert into t values(3,repeat('beijing 2008',2),md5(context));
Query OK, 1 row affected (0.00 sec)

mysql>  select * from t;
+------+--------------------------+----------------------------------+
| id   | context                  | hash_value                       |
+------+--------------------------+----------------------------------+
| 1    | beijingbeijing           | 09746eef633dbbccb7997dfd795cff17 |
| 2    | beijingbeijing           | 09746eef633dbbccb7997dfd795cff17 |
| 3    | beijing 2008beijing 2008 | 1c0ddb82cca9ed63e1cacbddd3f74082 |
+------+--------------------------+----------------------------------+
3 rows in set (0.00 sec)

mysql> select * from t where hash_value=md5(repeat('beijing 2008',2));
+------+--------------------------+----------------------------------+
| id   | context                  | hash_value                       |
+------+--------------------------+----------------------------------+
| 3    | beijing 2008beijing 2008 | 1c0ddb82cca9ed63e1cacbddd3f74082 |
+------+--------------------------+----------------------------------+

(3)對 BLOB 或者 CLOB 欄位進行模糊查詢,MySQL 提供了字首索引,也就是隻為欄位的前 n 列建立索引。

mysql> create index idx_blob on t(context(100));
Query OK, 0 rows affected (0.02 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> desc select * from t where context like 'beijing%' \G;
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: t
   partitions: NULL
         type: ALL
possible_keys: idx_blob
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 3
     filtered: 100.00
        Extra: Using where
1 row in set, 1 warning (0.00 sec)
# 請注意,這裡的查詢條件中,“%”不能放在最前面,否則索引將不會被使用。

(4)在不必要的時候避免檢索大型的 BLOB 或 TEXT 值。

(5)把 BLOB 或 TEXT 列分離到單獨的表中。

8.3 浮點數與定點數

浮點數一般用於表示含有小數部分的數值。插入資料超出實際精度,則插入值會被四捨五入到實際定義的精度值,然後插入,四捨五入的過程不會報錯。在 MySQL 中 float、double(或 real)用來表示浮點數。

定點數實際上是以字串形式存放的,定點數可以更加精確的儲存資料。如果實際插入的數值精度大於實際定義的精度,則 MySQL 會進行警告(預設的 SQLMode 下),但是資料按照實際精度四捨五入後插入;如果 SQLMode 是在 TRADITIONAL傳統模式下,則系統會直接報錯,導致資料無法插入。在 MySQL 中,decimal(或 hnumberic)用來表示定點數。

注意:在今後關於浮點數和定點數的應用中,使用者要考慮到以下幾個原則:

  • 浮點數存在誤差問題;
  • 對貨幣等對精度敏感的資料,應該用定點數表示或儲存;
  • 在程式設計中,如果用到浮點數,要特別注意誤差問題,並儘量避免做浮點數比較
  • 要注意浮點數中一些特殊值的處理。

8.4 日期型別選擇

選擇日期型別的原則:

  • 如果只需要記錄年份,只需要用一個位元組的YEAR型別完全可以滿足,而不需要四個位元組的DATE型別。
  • 如果要記錄年月日時分秒,並且記錄年份比較久遠,那麼最好使用DATETIME
  • 如果要記錄的日期要讓不同時區的使用者使用,那麼最好使用TIMESTAMP

延展閱讀

mysql的嚴格模式和寬鬆模式

mysql支援的sql_mode模式:ANSI、TRADITIONAL、STRICT_ALL_TABLES和STRICT_TRANS_TABLES。

ANSI模式:寬鬆模式,對插入資料進行校驗,如果不符合定義型別或長度,對資料型別調整或截斷儲存,報warning警告。

TRADITIONAL模式:嚴格模式,當向mysql資料庫插入資料時,進行資料的嚴格校驗,保證錯誤資料不能插入,報error錯誤。用於事務時,會進行事務的回滾。

STRICT_TRANS_TABLES模式:嚴格模式,進行資料的嚴格校驗,錯誤資料不能插入,報error錯誤。只對支援事務的表有效。

STRICT_ALL_TABLES模式:嚴格模式,進行資料的嚴格校驗,錯誤資料不能插入,報error錯誤。對所有表都有效。

# 檢視當前模式
select @@sql_mode;
show variables like '%mode%';
# 更改模式值:(1)命令列 (2)配置檔案 更多詳情見官網
# 有時候當像資料庫插入一個date型別為空或者不允許插入的字元的時候,可以通過設定sql_mode來允許操作
# 清空模式值[區域性]
set [global | session] sql_mode = "";