選擇數(shù)據(jù)類型的原則
1.更小的通常更好:一般情況下,應該盡量使用可以正確存儲數(shù)據(jù)的最小數(shù)據(jù)類型眉枕。更小的數(shù)據(jù)類型通常更快恶复,因為它們占用更少的磁盤、內存和CPU緩存速挑,并且處理時需要的CPU周期也更少寂玲。
2.簡單就好:簡單數(shù)據(jù)類型的操作通常需要更少的CPU周期。例如梗摇,整型比字符操作代價更低拓哟,因為字符集和校對規(guī)則(排序規(guī)則)使字符比較比整型比較更復雜。這里有兩個例子:一個是應該使用MySQL內建的類型而不是字符串來存儲日期和時間伶授,另外一個是應該用整型存儲IP地址断序。
3.盡量避免NULL:如果查詢中包含可為NULL的列,對MySQL來說更難優(yōu)化糜烹,因為可為NULL的列使得索引統(tǒng)計和值比較都更復雜违诗。可為NULL的列會使用更多的存儲空間疮蹦,在MySQL利也需要特殊處理诸迟。當可為NULL的列被索引時,每個索引記錄需要一個額外的字節(jié),在MyISAM里甚至還可能導致固定大小的索引(例如只有一個整數(shù)列的索引)變成可變大小的索引阵苇。
InnoDB使用單獨的位(bit)存儲NULL值壁公,所以對于稀疏數(shù)據(jù)有很好的空間效率。
整數(shù)類型
TINYINT绅项,SMALLINT紊册,MEDIUMINT,INT快耿,BIGINT囊陡。分別使用8,16掀亥,24撞反,32,64位存儲空間搪花。它們可以存儲的值的范圍從-2的(N-1)次方到2的(N-1)次方減一遏片,其中N是存儲空間的位數(shù)。
整數(shù)類型有可選的UNSIGNED屬性鳍侣,表示不允許負值,這大致可以使正數(shù)的上限提高一倍吼拥。例如TINYINT UNSIGNED可以存儲的范圍是0~255倚聚,而TINYINT的存儲范圍是-128~127。因此可以根據(jù)實際情況選擇合適的類型凿可。
MySQL可以為整數(shù)類型制定寬度惑折,例如INT(11),對大多數(shù)應用這是沒有意義的:他不會限制值的合法范圍枯跑,只是規(guī)定了MySQL的一些交互工具(例如命令行)用來顯示字符個數(shù)惨驶。對于存儲和計算來說,INT(1)和INT(20)是相同的敛助。
實數(shù)類型
實數(shù)是帶有小數(shù)部分的數(shù)字粗卜。但是不只是為了存儲小數(shù),也可以用DECIMAL存儲比BIGINT還大的整數(shù)纳击。
FLOAT和DOUBLE類型支持使用標準的浮點運算進行近似計算续扔。DECIMAL類型用于存儲精確的小數(shù),并且它可以指定小數(shù)點前后的所允許的最大位數(shù)焕数。這會影響列的空間消耗纱昧。在較高的版本將會把數(shù)字打包保存到一個二進制字符串中(每4個字節(jié)存9個數(shù)字)。例如DECIMAL(18堡赔,9)小數(shù)點兩邊將各存儲9個數(shù)字识脆,一共使用9個字節(jié):小數(shù)點前的數(shù)字用4個字節(jié),小數(shù)點后的數(shù)字用4個字節(jié),小數(shù)點本身占1個字節(jié)灼捂。而DECIMAL類型允許最多65個數(shù)字离例,注意DECIMAL只是一種存儲格式,計算時會轉換為DOUBLE類型纵东。DOUBLE是MySQL內部計算類型粘招。
浮點類型在存儲同樣范圍的值時,通常比DECIMAL使用更少的空間偎球。FLOAT使用4個字節(jié)存儲洒扎。DOUBLE占用8個字節(jié),相比FLOAT有更高的精度和更大的范圍衰絮。
由于消耗問題袍冷。所以應該有小數(shù)精確計算時才用DECIMAL。另外猫牡,某些場合可以考慮用BIGINT代替DECIMAL胡诗,比如存儲財務數(shù)據(jù),可以將需要存儲的貨幣單位根據(jù)小數(shù)的位數(shù)乘以相應的倍數(shù)淌友,然后用BIGINT存儲煌恢。
字符串類型
VARCHAR和CHAR類型
VARCHAR:VARCHAR類型用于存儲可變長字符串,因此它僅使用必要的空間震庭,它比定長類型更節(jié)省空間瑰抵。VARCHAR需要使用1或2個額外字節(jié)記錄字符串的長度,如果列的最大長度小于或等于255字節(jié)器联,則只使用1個字節(jié)表示二汛,否則使用2個字節(jié)。
VARCHAR節(jié)省了存儲空間拨拓,所以對性能也有幫助肴颊。但是,由于行是變長的渣磷,在UPDATE時可能使行變得更長婿着,這就需要做額外的工作。如果一個行占用的空間增長醋界,并且在頁內沒有更多的空間可以存儲祟身,這種情況下,不同的存儲引擎的處理方式不一樣物独。例如MyISAM會將行拆成不同的片段存儲袜硫,InnoDB則需要分裂頁來使行可以放進頁內。這樣一來就會產(chǎn)生很多內存碎片挡篓。
根據(jù)上面的描述可以確定VARCHAR適合的情況:
1.字符串列的最大長度比平均長度大很多婉陷;
2.列的更新很少所以碎片不是問題帚称;
3.使用了像UTF-8這樣復雜的字符集,每個字符都使用不同的字節(jié)數(shù)進行存儲秽澳。
CHAR:CHAR類型是定長的闯睹,MySQL總是根據(jù)定義的字符串長度分配足夠的空間。當存儲CHAR值時担神,MySQL會刪除所有的末尾空格
1.CHAR適合存儲很短的字符串楼吃,或所有值都接近同一個長度。例如妄讯,CHAR非常適合存儲密碼的MD5值孩锡,因為這是一個定長的值。
2.對于經(jīng)常變更的數(shù)據(jù)亥贸,CHAR也比VARCHAR更好躬窜,因為定長的CHAR類型不容易產(chǎn)生碎片。
3.對于非常短的列炕置,CHAR也比VARCHAR在存儲空間上也更有效率荣挨。例如用CHAR(1)來存儲只有Y和N的值,如果采用單字符集只需一個字節(jié)朴摊,但是VARCHAR(1)卻需要兩個字節(jié)默垄,因為還有一個記錄長度的額外字節(jié)。
注:使用VARCHAR(5)和VARCHAR(200)存儲較小的數(shù)據(jù)時甚纲,雖然空間開銷一樣口锭,但是還是用VARCHAR(5)比較好。因為更長的列會消耗更多的內存贩疙,MySQL通常會分配固定大小的內存塊來保存內部值讹弯。所以最好的策略就是分配真正需要的空間况既。
日期和時間類型
DATETIME
這個類型能保存大范圍的值这溅,從1001年到9999年,精度為秒棒仍。他把日期和時間封裝到格式為YYYYMMDDHHMMSS的整數(shù)中悲靴,與時區(qū)無關。使用8個字節(jié)的存儲空間莫其。默認情況下癞尚,MySQL以一種可排序的格式顯示DATETIME值。
TIMESTAMP
保存了從1970年1月1日午夜以來的秒數(shù)乱陡。它只使用4個字節(jié)的存儲空間浇揩,因此它的范圍比DATETIME小的多。
TIMESTAMP顯示的值也依賴于時區(qū)憨颠,MySQL服務器胳徽、操作系統(tǒng)积锅,以及客戶端連接都有時區(qū)設置。
應該多用TIMESTAMP因為它比DATETIME空間效率更高养盗。