设计数据库表时,你真的会选数据类型吗
轉(zhuǎn)載自??設計數(shù)據(jù)庫表時,你真的會選數(shù)據(jù)類型嗎
關系型數(shù)據(jù)庫,是開發(fā)人員最常接觸的持久化存儲之一了,使用關系型數(shù)據(jù)庫有很多好處,比如支持通過事務處理保持數(shù)據(jù)的一致性、數(shù)據(jù)更新的開銷很小、可以進行Join等復雜查詢等。
同時,還有個好處就是關系型數(shù)據(jù)庫有比較完善的數(shù)據(jù)類型,支持很多不同類型的數(shù)據(jù)存儲。但是這些數(shù)據(jù)類型的使用和選擇也有很多套路在的,本文就來簡單介紹一下。
1.?整數(shù)類型
整數(shù)類型有:tinyint、smallint、mediumint、int、bigint,分別使用 8、16、24、32、64 位存儲空間。
它們可以存儲的值范圍從 -2 的 (n-1) 次方到 2 的 (n-1) 次方 -1,n 是存儲空間的位數(shù)。
整數(shù)有可選的 unsigned 屬性(無符號類型),表示不允許有負值,因此可以使正數(shù)上限提高一倍。
有符號和無符號類型使用相同的存儲空間,并具有相同的性能,因此可以根據(jù)實際情況選擇合適的類型。
?
2.? 實數(shù)類型
實數(shù)類型有:FLOAT、DOUBLE ,分別占用 4,8 字節(jié)。
如果插入值的精度(即:數(shù)字總位數(shù))高于實際定義的精度,系統(tǒng)會自動進行四舍五入處理,使值的精度達到要求。
其中 DECIMAL 也可以用來指定精度,并且它比 FLOAT 和 DOUBLE 更適合做精確計算。在本文就不做詳細介紹了,如果有人想了解的話可以給我留言,我下次再寫。
?
3. 字符串類型
字符串類型有:
VARCHAR
CHAR
BLOB
TEXT
由于 BLOB 和 TEXT 不常用且由于篇幅問題,就不展開描述了。本文主要對 VARCHAR 和 CHAR 進行介紹,它們的區(qū)別如下表:
| 是否固定長度 | 否 | 是 |
| 存儲上限字節(jié) | 65535 | 255 |
| 保存或檢索值時,是否刪除字符串末尾空格 | 否 | 是 |
| 超過設置的范圍后,字符串是否會被截斷 | 否 | 是 |
除了以上不同之外,VARCHAR 還需要額外使用 1 個或 2 個字節(jié)來記錄字符串長度。如果列的最大長度小于或等于 255 字節(jié),則使用 1 個字節(jié),否則使用 2 個字節(jié)。
由于 VARCHAR 是變長的,所以在 update 時,可能使行變得比原來更長,這就導致需要進行額外的工作。如果一個行占用的空間增加,并且在頁內(nèi)沒有更多空間可以存儲,在這種情況下,不同存儲引擎的處理方式不一樣的。例如:MyISAM 會將行拆分為不同的片段存儲,InnoDB 則需要分裂頁來使行可以放進頁內(nèi)。
在選擇使用場景上,重點要抓住 VARCHAR 是變長,CHAR 是定長的特點。
比如在這些情況更適合使用 VARCHAR:
-
字符串的最大長度比平均長度大很多;
-
字段更新次數(shù)少(所以碎片不是問題);
-
使用了像 UTF-8 這樣復雜的字符集,每個字符都使用不同的字節(jié)數(shù)進行存儲。
而在這些情況則更適合使用 CHAR:
-
存儲很短的字符串(而 VARCHAR 還要多一個字節(jié)來記錄長度,本來打算節(jié)約存儲的現(xiàn)在反而得不償失)
-
定長的字符串(如 MD5、uuid);
-
需要頻繁修改的字段。因為 VARCHAR 每次存儲都要有額外的計算,得到長度等工作;
這里拋出一個小問題:使用 VARCHAR(5) 和 VARCHAR(200) 來存儲 ‘hello’ 的空間開銷是一樣的。那么使用更短的列有什么好處呢?(思考幾秒鐘?)
答案:節(jié)約內(nèi)存,因為更長的列會消耗更多的內(nèi)存。MySQL 通常會分配固定大小的內(nèi)存塊來保存內(nèi)部值。尤其是使用內(nèi)存臨時表進行排序或操作時會特別糟糕。在利用磁盤臨時進行排序時也同樣糟糕。
所以最好的策略是只分配真正需要的空間。
?
4. 日期和時間類型
下面表格是 TIMESTAMP 和 DATETIME 的一些對比:
| 占用字節(jié) | 4 | 8 |
| 時間范圍 | 1970-01-01 08:00:01 ~ 2038-01-19 11:14:07 | 1000-01-01 00:00:00 ~ 9999-12-31 23:59:59 |
| 存儲的數(shù)據(jù)是否隨時區(qū)變化 | 是 | 否 |
如果在插入數(shù)據(jù)時,沒有指定第一個 TIMESTAMP 列的值,MySQL 則將這個列設置為當前時間,同時 TIMESTAMP 比 DATETIME 的空間效率更高。
最后,網(wǎng)上有很多討論,時間到底要使用 INT、TIMESTAMP、DATETIME 哪種類型更適合。我認為這沒有一個固定答案,具體可以參考文章:《選擇合適的 MySQL 日期時間類型來存儲你的時間》,我放在原文鏈接里面了。
?
5. 設計合理的數(shù)據(jù)類型
提供給大家 3 點設計原則:
更小的通常更好
簡單就好
盡量避免 NULL
下面對其詳細說明一下:
一般情況下,應該選擇可以正確存儲數(shù)據(jù)的最小數(shù)據(jù)類型,因為它們占用更少的磁盤、內(nèi)存和 CPU 緩存,并且處理時需要的 CPU 周期也更少。
簡單數(shù)據(jù)類型的操作需要更少的 CPU 周期。例如,整型比字符操作代價更低,因為字符集和校對規(guī)則(排序規(guī)則)使字符比較比整型比較更復雜。
通常情況下,最好指定列為 NOT NULL,除非真的需要存儲 NULL 值。因為可為 NULL 的列會使索引、索引統(tǒng)計和值比較都更復雜。可為 NULL 的列會使用更多的存儲空間,在 MySQL 里也需要特殊處理。
當可為 NULL 的列被索引時,每個索引需要一個額外的字節(jié),在 MyISAM 里甚至還可能導致固定大小的索引變成可變大小的索引。通常把可為 NULL 的列改為 NOT NULL 帶來的性能比較小,所以在優(yōu)化時沒有必要先在現(xiàn)有表里修改這種情況。
參考:
-
《高性能 MySQL》
總結
以上是生活随笔為你收集整理的设计数据库表时,你真的会选数据类型吗的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 介绍Jambo!Joomla可爱的非官方
- 下一篇: MySQL 大表优化方案(1)