數據庫——字段類型

數據庫的字段類型

今天對數據庫中的一些數據類型進行總結。

MySQL數據類型選取的原則

(1)更小通常更好
一般情況下,應該儘量使用可以正確存儲數據的最小數據類型。更小的數據類型通常更快,因爲它們佔用更少的磁盤、內存和CPU緩存,並且處理時需要的CPU週期也更少。
(2)簡單更好
簡單的數據類型的操作通常需要更少的CPU週期。例如整形比字符操作代價更低,因爲字符集的校對規則(排序規則)使字符比較比整形比較更復雜。這裏有兩個例子:一個是應該使用MySQL內建的類型而不是字符串來存儲日期和時間,另外一個是應該用整形存儲IP地址。
(3)儘量避免NULL
很多表都包含可爲NULL(空值)的列,即使應用程序並不需要保存NULL也是如此,這是因爲可爲NULL是列的默認屬性。通常情況下最好指定列爲NOT NULL,除非真的需要存儲NULL值。
如果查詢中包含可爲NULL的列,對於MySQL來說更難優化,因爲可爲NULL的列使得索引、索引統計和值比較都更復雜。可爲NULL的列會使用更多的存儲空間,在MySQL中也需要特殊處理。當可爲NULL的列被索引時,每個索引記錄需要一個額外的字節,在MyISAM裏甚至還可能導致固定大小的索引(例如一個整數列的索引)變成可變大小的索引。
通常把可爲NULL的列改爲NOT NULL帶來的性能提升比較小,所以(調優時)沒有必要首先在現有schema中查找並修改掉這種情況,除非確定這會導致問題。但是,如果計劃在列上建索引,就應該儘量避免設計成可爲NULL的列。
當然也有例外,例如值得一提的是,InnoDB使用單獨的位(bit)存儲NULL值,所以對於稀疏數據有很好的空間效率。這一點不適用於MyISAM。

數字類型

整數類型

有兩種數字類型:整數(whole number)和實數(real number)。如果存儲整數,可以使用這幾種整數類型:TINYINT,SMALLINT,MEDIUMINT,INT,BIGINT。分別使用9,16,24,32,64位存儲空間。它們可以存儲的值的範圍是-2(N-1) 到2(N-1) -1,其中N是存儲空間的位數。
整數類型有可選的UNSIGNED屬性,表述不允許負值,這大致可以使正數的上限提高一倍。例如TINYINT.UNSIGNED可以存儲的範圍是0~255,而TINYINT的存儲範圍是-128 ~ 127.
注意: MySQL可以爲整數指定寬度,例如INT(11),對大多數應用這是沒有意義的:它不會限制值的合法範圍,只是規定了MySQL的一些交互工具(例如MySQL 命令行客戶端)用來顯示字符的個數。對於存儲和計算來說,INT(1)和INT(20)是相同的。

實數類型

實數是帶有小數部分。除了存儲小數部分,也可以使用Decimal存儲比BIGINT還大的整數。MySQL即支持精確類型,也支持不精確類型。
FLOAT和DOUBLE類型支持使用標準的浮點運算進行近似計算。
DECIMAL類型用於存儲精確的小數。在MySQL5.0和更高版本,DECIMAL支持精確計算。因爲CPU不支持對DECIMAL的直接計算,所以在MySQL5.0以及更高版本中,MySQL服務自身實現了DECIMAL的高精度計算。

因爲需要額外的空間和計算開銷,所以應該儘量只對小數進行精確計算的時候纔是用DECIMAL——例如存儲財務數據。但在數據量比較大的時候,可以考慮使用BIGINT代替DECIMAL,將需要存儲的貨幣單位根據小數的位數乘以相應的倍數即可。假設要存儲財務數據精確到萬分之一分,則可以把所有金額乘以一百五,然後將結果存儲在BIGINT裏,這樣可以同時避免浮點存儲計算不精確和DECIMAL精確計算代價高的問題。

字符串類型

VARCHAR

VARCHAR類型用於存儲可變長字符串,是最常見的字符串數據類型。它比定長類型更節省空間,因爲它僅適用必要的空間(例如,越短的字符串適用越少的空間)。有一種情況例外,如果MySQL表適用ROW_ROTMAT=FIXED創建的話,每一行都會使用定長存儲,這會很浪費空間。

VARCHR需要使用1 或 2 個額外字節記錄字符串的長度:如果列的最大長度小於或等於255字節,則只使用1個字節表示,否則使用2個字節。

適合使用VARCHAR的情況:
(1)字符串列的最大長度比平均長度達很多;
(2)列的更新很少,所以碎片不是問題;
(3)使用了像UTF-8這樣複雜的字符集,每個字符都使用不同的字節數進行存儲。

CHAR

CHAR類型是定長的:MySQL總是根據定長的字符串長度分配足夠的爲空間。
CHAR的適用場景
(1)CHAR使用存儲很短的字符串,或者所有值都接近同一個長度。列如CHAR非常適合存儲密碼的MD5值,因爲這是一個定長的值。
(2)對於經常變更的數據,CHAR也比VARCHAR更好,因爲定長的CHAR類型不容易產生碎片。
(3)對於非常短的列,CHAR比VARCHAR在存儲空間上也更有效率。例如CHAR(1)來存儲只有Y和N的值,如果採用單字節字符集只需要一個字節,但是VARCHAR(1)確需要兩個字節,因爲還有一個額外記錄長度的額外字節。

BINARY和VARBINARY

BINARY和VARBINARY存儲的是二進制字符串。與CHAR和VARCHAR類似,分別存儲定長和邊長的二進制字符串。
使用場景:
當需要存儲二進制數據,並且希望MySQL使用字節碼而不是字符進行比較時,這些類型是非常有用的。二進制比較不僅僅體現在大小寫敏感上。MySQL比較BINARY字符串時,每次按一個字節,並且根據該字節的值進行比較。因此二進制比較比字符串簡單很多,所以也就更快。

使用VARCHAR(5)和VARCHAR(200)存儲’hello’的空間開銷是一樣的。那麼使用更短的列有什麼優勢嗎?
事實證明有很大的優勢。更長的列會消耗更多的內存,因爲MySQL通常會分配固定大小的內存塊來保存內部值。尤其是使用內存臨時表進行排序或操作時會特別糟糕。在利用磁盤臨時表進行排序時也同樣糟糕。
所以最好的策略是隻分配真正需要的空間。

BLOB和TEXT類型

BLOB和TEXT是爲了存儲很大的數據而設計的字符串數據類型,分別採用二進制和字符方式存儲。
實際上,它們分別屬於兩組不同的數據類型家族:字符類型是TINYTEXT,SMALLTEXT,TEXT,MEDINUMTEXT,LONGTEXT;
對應的二進制類型是TINYBLOB,SMALLBLOB,BLOB,MEDIUMBLOB,LONGBLOB。BLOB是SMALLBLOB的同義詞,TEXT是SMALLTEXT的同義詞。

與其他類型不同MySQL把每個BLOB和TEXT值當作一個獨立的對象處理。存儲引擎在存儲時通常會做特殊處理。當BLOB和TEXT值太大時,InnoDB 會使用專門的“外部”存儲區域來進行存儲,此時每個值在行內需要1~4個字節存儲一個指針,然後在外部存儲區域存儲實際的值。

BLOB和TEXT家族之間僅有的不同是BLOB類型存儲的是二進制數據,沒有排序規則和字符集,而TEXT類型有字符集合排序規則。

MySQL對BLOB和TEXT列進行排序與其他類型是不同的:它只對每個列的最前max_sort_length字節而不是整個字符串做排序。如果只需要排序前面小部分字符,則可以減小max_sort_length的配置,或者使用ORDER BY SUBSTRING(coimn,length).

我們應該避免使用BLOB和TEXT。

使用枚舉(ENUM)代替字符串類型

枚舉可以把一些不重複的字符串存儲爲一個預定義的集合。

日期和時間類型

MySQL提供兩種相似的日期類型:DATETIME和TIMESTAMP。

DATETIME

這個類型能保存大範圍的值,從1001年到9999年,精確到秒。它把日期和時間封裝到格式爲TTTTMMDDHHMMSS的整數中,與時區無關。使用8個字節的存儲空間。
默認情況下,MySQL以一種可排序的,無歧義的格式顯示DATETIME 值,例如“2008-01-16 22:37:08”。

TIMESTAMP

TIMESTAMP類型保存了從1970年1月1日午夜以來的秒數,它與UNIX時間戳相同。TIMESTAMP使用4個字節的存儲空間,因此它的範圍比DATETIME小的多:只能表示1970到2038年MySQL提供了FROM_UNIXTIME()函數把Unix時間戳轉換爲日期,並提供了UNIX_TIMESTAMP()函數把日期轉換爲Unix時間戳。

關於日期的存儲,除了特殊行爲之外,通常應該儘量使用TIMESTAMP,因爲它比DATETIME空間效率更高。不建議用整數來保存時間戳的格式,因爲處理不方便。

如何存儲比秒更小粒度的日期和時間值?
MySQL能存儲的粒度到秒,但是可以使用自己的存儲格式:可以使用BIGINT類型存儲微妙級別的時間戳,或者使用double存儲秒後面的的小數部分。

位數據類型

BIT

MySQL會把BIT數據類型當做字符串來處理,如存儲一個值爲b’0011001的列並且檢索它,得到的內容是57的字符串,MySQL將其作爲字符串來處理,並且轉爲相應的數字。因此不建議使用BIT數字類型。
如果想在一個bit的存儲空間存儲一個true/false值,另一個方法是創建一個可以爲空的CHAR(0)列。該列可以保存空值(NULL )或者長度爲零的字符串(空字符串)。

一些相關的題目

在表Dept(Dno,Dname,Tele)中,爲了儘量減小存儲空間,字段Dname存儲長度在6-18之間,以下設置的字段類型哪個最合適
A Varchar(10)

B Varchar(20)

C Char(20)

D char(10)
根據上面對VARCHAR和CHAR的總結,我們可以得出答案,使用B。

參考資料

高性能MySQL第三版

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章