最近須要對錶加一個字段,同時以爲前期創建表的時候有點粗暴,沒有加很對限制,好比有些字符串長度是有限制的,在建立表時字段也沒有對其進行限制。因此想借着此次加字段對錶字段也進行一個優化,在優化以前先看了點理論知識,理論指導實踐mysql
選擇合適的字段類型既能夠節省空間,又能夠在查詢上提升效率,所以字段類型選擇是很重要的。本篇文章將介紹經常使用字段類型:sql
整數類型有TINYINT,SMALLINT,MEDIUMINT,INT,BIGINT,存儲空間及數值範圍以下表數據庫
類型 | 存儲空間(單位爲位) | 數值範圍 |
---|---|---|
TINYINT | 8 | -128 ~ 127 |
SMALLINT | 16 | -32768 ~ 32767 |
MEDIUMINT | 24 | -8388608 ~ 8388607 |
INT | 32 | -2147483648 ~ 2147483647 |
BIGINT | 64 | 太大了 |
數值範圍爲-2^(N-1) ~ 2^N, 其中N爲存儲空間大小緩存
整數類型有可選的UNSIGNED屬性,不容許出現負值。設置UNSIGNED屬性可使正數的上限提升一倍,數值範圍大小爲 0 ~ 2^(N-1) + 2^Nbash
通常選擇最小的可以知足存儲的類型就行,更小的數據類型一般更快,佔用更少的磁盤、內存和CPU緩存。處理時須要的CPU週期也更少post
單精度浮點型,使用8位性能
雙精度浮點型,使用16位存儲優化
float和double進行計算時會發生精度損失,損精度損失緣由可參考這篇文章:老闆,用float存儲金額爲何要扣我工資 須要精度計算的時候可使用DECIMAL,使用DECIMAL須要額外的空間和計算開銷,所以當且僅當須要精度計算時才使用spa
varchar和char是很是很是經常使用的字符串類型3d
VARCHAR用於存儲變長字符串,使用該類型存儲字符串時須要額外使用1或2個額外字節記錄字符串的長度:
適用VARCHAR做爲存儲類型的場景:
CHAR用於存儲定長字符串,在存儲CHAR類型時,會刪除全部的末尾空格
使用CHAR最爲存儲類型的場景
BLOB和TEXT類型都是用來存儲很大的數據,好比文章內容這些
採用二進制方式存儲, BLOB細分又能夠分爲TINYBLOB,SMALLBLOB,BLOB,MEDIUMBLOB, LONGBLOB
採用字符方式存儲,TEXT細分又能夠分爲TINYTEXT,SMALLTEXT,TEXT,MEDIUMTEXT, LONGTEXT
當BLOB和TEXT值太大時,InnoDB存儲會使用外部存儲區域來存儲值,而後保存一個1~4字節的指針指向外部存儲
經常使用的日期類型有DATETIME和TIMESTAMP
使用8字節存儲,能夠保存大範圍的值,從1001~9999年
使用4字節存儲,保存範圍比DATETIME小,從1970~2038年
對於須要存儲更小粒度的日期和時間可使用DOUBLE或BIGINT,固然不是存儲小粒度也可使用BIGINT
以前曾由於時間類型搞出過線上慢查詢,這篇文章記錄了慢查詢緣由:很高興!終於踩到了慢查詢的坑, 對於須要對時間進行範圍查找、排序、分組等操做之類的建議使用BIGINT,若是對時間類型字段沒有任何操做,建議使用TIMESTAMP,能夠參考這篇文章:mysql數據庫時間類型datetime、bigint、timestamp的查詢效率比較
在stackoverflow下找到以下:
可使用枚舉列代替經常使用的字符串類型,經過枚舉能夠限制值的取值範圍
建立表語句:
CREATE TABLE `dataset_enum` (
`name` varchar(48) DEFAULT NULL,
`status` enum('NEW','UPLOADING','USING','DELETING') DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8
複製代碼
插入語句:
insert into dataset_enum(name, status) values("t4", "DELETING")
複製代碼
對於status字段底層存儲的是整數而不是字符串,在底層會維護一個 數字 - 字符串的映射關係
查詢語句並根據status字段進行排序:
select * from dataset_enum order by status;
複製代碼
查詢結果:
+------+-----------+
| name | status |
+------+-----------+
| t1 | NEW |
| t2 | UPLOADING |
| t4 | DELETING |
+------+-----------+
複製代碼
說明:
以前建立表的時候對於經常使用字符串的代替選擇的都是TINYINT類型,應用層在作轉換。當看到ENUM類型時有點困惑,爲何沒選擇使用ENUM而是TINY,網上查找了一下緣由,以下圖:
總結緣由以下:
mysql> insert into dataset_enum values("t1", "NEW"), ("t2", 2);
Query OK, 2 rows affected (0.01 sec)
Records: 2 Duplicates: 0 Warnings: 0
複製代碼
成功插入了數據 查詢數據:mysql> select * from dataset_enum;
+------+-----------+
| name | status |
+------+-----------+
| t1 | NEW |
| t2 | UPLOADING |
+------+-----------+
複製代碼
數值類型作轉化之後也能夠插入參考文章:
Should I use the datetime or timestamp data type in MySQL?
8 Reasons Why MySQL's ENUM Data Type Is Evil 爲何辣麼多人喜歡用 tinyint而不用 enum? 《高性能MySQL》