前段時間看了《高效能MySQL》中的選擇優化的資料型別,這裡主要是做一下筆記。
首先資料選擇有幾個簡單原則:
- 更小的通常更好。一般情況下,應該儘量使用可以正確儲存資料的最小資料型別。例如只需要存 0~200,tinyint unsigned 更好。更小的資料型別通常更快,因為它們佔用更少的磁碟、記憶體和 CPU 快取,並且處理時需要的 CPU 週期也更少。
- 簡單就好。簡單資料型別的操作通常需要更少的 CPU 週期。例如,整型比字元操作代價更低,因為字符集和校對規則(排序規則)使字元比較 比 整型比較更復雜。這裡有兩個例子:一個是應該使用 MySQL 內建的型別(date, time, datatime)而不是字串來儲存日期和時間,另一個是應該用無符號整型儲存 IP 地址。
- 儘量避免NULL。通常情況下最好指定列為 NOT NULL,除非真的需要儲存 NULL 值。如果查詢中包含可為 NULL 的列,對 MySQL 來說更難優化,因為可為 NULL 的列使得索引、索引統計和值比較都更復雜。特別是計劃在列上建索引,就應該儘量避免設計成可為 NULL 的列。
整數型別:(tinyint,smallint,mediumint,int,bigint)
儲存(位元組) | 儲存(位) | 有符號範圍 | 無符號範圍 | |
TINYINT | 1 | 8 | -128 ~127 | 0~255 |
SMALLINT | 2 | 16 | -32768~32767 | 0~65535 |
MEDIUMINT | 3 | 24 | -8388608~8388607 | 0~16777215 |
INT | 4 | 32 | -2147483648~2147483647 | 0~4294967295 |
BIGINT | 8 | 64 | -2^63~2^63-1 | 0~2^64-1 |
- 整數型別有可選的 unsigned 屬性,表示不允許負值,這大致可以使正數的上限提高一倍。主鍵自增 id 適合設定為 unsigned 屬性的 int 型別。
- MySQL 可以為整數型別指定寬度,例如 int(11),對大多數應用這是沒有意義的:它不會限制值的合法範圍,只是規定了 MySQL 的一些互動工具(例如 MySQL 命令列客戶端)用來顯示字元的個數。對於儲存和計算來說,int(1) 和 int(20) 是相同的。
實數型別:(float,double,decimal)
- float,double 屬於浮點型別(近似值)。decimal 屬於定點型別(精確值)。
- MySQL 浮點型和定點型可以用型別名稱後加(M,D)來表示,M 表示該值的總共長度,D 表示小數點後面的長度。
- float 使用 4 個位元組儲存;double 使用使用 8 個位元組儲存;decimal 則是將數字打包儲存到一個二進位制字串中(每 4 個位元組存 9 個數字)。例如,decimal(18, 9) 小數點兩邊將各儲存 9 個數字,一共使用 9 個位元組:小數點前的數字用 4 個位元組,小數點後的數字用 4 個位元組,小數點本身佔 1 個位元組。
- 因為需要額外的空間和計算開銷,所以應該儘量只在對小數進行精確計算時才使用 decimal——例如儲存財務資料。但在資料量比較大的時候,可以考慮使用 bigint 代替 decimal ,將需要儲存的貨幣單位根據最小的位數乘以相應的倍數即可。
字串型別:
varchar 和 char 型別
- varchar 型別用於儲存可變長字串,是最常見的字串資料型別。
- varchar 需要使用 1 或 2 個額外位元組記錄字串長度:如果列的最大長度小於或等於 255 位元組,則只使用 1 個位元組表示,否則使用 2 個位元組。
- char 型別是定長的:MySQL 總是根據定義的字串長度分配足夠的空間。
- char 儲存會刪除儲存資料的末尾空格;varchar 不會。(準確來說是 MySQL 4.1 以後的版本 varchar 不會刪除儲存資料的末尾空格)
blob 和 text 型別
- blob 和 text 都是為了儲存很大的資料而設計的字串資料型別,分別採用二進位制和字元方式儲存。
- 與其它型別不同,MySQL 把每個 blob 和 text 值當作一個獨立的物件處理。
- blob 和 text 家族之間僅有的不同是 blob 型別儲存的是二進位制資料,沒有排序規則或字符集,而 text 型別有字符集和排序規則。
- memory 引擎不支援 blob 和 text 型別。
列舉(enum)型別
- MySQL 在內部會將每個值在列表中的位置儲存為整數,並且在表的 .frm 檔案中儲存 “數字-字串” 對映關係的 “查詢表”。
- 如果使用數字作為列舉常量,這種雙重性很容易導致混亂,例如 enum(`1`, `2`, `3`) 。建議儘量避免這麼做。
- 列舉欄位是按照內部儲存的整數而不是定義的字串進行排序的。
日期和時間型別:
- MySQL 能儲存的最小時間粒度為秒。
- datetime 儲存範圍從 1001 年到 9999 年,精度為秒。與時區無關。使用 8 位元組的儲存空間。
- timestamp 型別儲存了從 1970 年 1 月 1 日 午夜(格林尼治標準時間)以來的秒數,它和 unix 時間戳相同。使用 4 位元組的儲存空間,範圍從 1970 年到 2038 年。與時區有關。
- MySQL 4.1 以及更新的版本按照 datetime 的方式格式化 timestamp 的值,這僅僅是顯示格式上的區別,timestamp 的儲存格式在各個版本都是一樣的。
- 除了特殊行為之外,通常也應該儘量使用 timestamp ,因為它比 datetime 空間效率更高。有時候人們會將 unix 時間戳儲存為整數值,但這不會帶來任何收益。用整數儲存時間戳的格式通常不方便處理,所以我們不推薦這麼做。(對於這點很多公司專案中是用整數儲存,我也查了資料,使用整數的理由一般是日期比較,計算時整數更好處理)