MySQL Schema與數(shù)據(jù)類型的優(yōu)化
選擇優(yōu)化的數(shù)據(jù)類型:
1、 更小的通常更好:
一般情況下,應(yīng)該盡量使用可以正確存儲數(shù)據(jù)的最小數(shù)據(jù)類型。更小的數(shù)據(jù)類型通常更快,因為他們占用更少的磁盤,內(nèi)存和cpu緩存,并且處理時需要的cpu周期也更少。
2、 簡單就好
簡單的數(shù)據(jù)類型操作通常需要更少的cpu周期。例如,整型比字符操作代價更低,因為字符集和校對規(guī)則(排序規(guī)則)使字符比較比整型更加復(fù)雜。注:應(yīng)使用mysql內(nèi)建的類型存儲時間和日期,而不是字符串。
3、 盡量避免null
如果查詢中包含可為null的列,對Mysql來說更難優(yōu)化,因為可為null的列使得索引、索引統(tǒng)計和值都比較復(fù)雜。可為null的列會使用更多的存儲空間,在mysql中也需要特別處理。當(dāng)可為null的列被索引時,每個索引記錄需要一個額外的字節(jié)。
通常把可為null的列改為not null帶來的性能提升比較小。在調(diào)優(yōu)時,沒有必要首先在現(xiàn)有的shema中查找并修改掉這個情況,除非確定這會導(dǎo)致問題。但是如果列上建索引,就應(yīng)盡量避免設(shè)計成可為null的列。
整數(shù)類型:
整數(shù)類型有TINYINT,SMALLINT,MEDIUMINT,INT,BIGINT。分別使用8,16,24,32,64位存儲空間。他們可以存儲的值的范圍從-2的(n-1)次方到2的(n-1)次方-1,其中n是存儲空間的位數(shù)。
整數(shù)類型有可選的UNSIGNED屬性,表示不允許負值,這大致可以是正數(shù)的上限提高一倍。例如TINYINT UNSIGNED可以存儲的范圍是0~255,而TINYINT的存儲范圍是-128~127。
實數(shù)類型:
實數(shù)是帶有小數(shù)部分的數(shù)字。然后,他們不僅僅為了存儲小數(shù)部分;也可以使用DECIMAL存儲比BITINT還大的整數(shù)。MYSQL既支持精確類型,也支持不精確類型。
DECIMAL類型用于存儲精確的小數(shù),因為double類型和float類型在進行計算時,會因為精度損失導(dǎo)致一些數(shù)據(jù)的偏差。但是DECIMAL數(shù)據(jù)類型cpu不支持對其直接計算,cpu直接支持原生浮點計算,所以浮點運算明顯更快。
因為需要額外的空間和計算開銷,所以應(yīng)該盡量只在對小數(shù)進行精確計算時才使用DECIMAL-例如存儲財務(wù)數(shù)據(jù)。但是在數(shù)據(jù)量比較大的時候,可以考慮使用BITINT代替DECIMAL,將需要存儲的貨幣單位根據(jù)小數(shù)的位數(shù)乘以相應(yīng)的倍數(shù)即可。
字符串類型(varchar和char)
- Varchar:
Varchar類型用于存儲可變長字符串,是最常見的字符串類型。他比定長類型更節(jié)省空間,因為它僅使用必要的空間(例如,越短的字符串使用越少的空間)。所以,varchar節(jié)省了存儲空間,對性能也有幫助。但是,由于行是邊長的,在update是可能使行變得比原來更長,這就導(dǎo)致需要做額外的操作。如果一個行占用的空間增長,并且頁內(nèi)沒有更多的空間存儲。MyISAM會將行拆成不同的片段存儲,InnoDB則需要分裂頁來使行可以放進頁內(nèi)。
注:InnoDB更加靈活,它可以把過長的varchar存儲為BLOB。
- Char類型:
Char類型適合存儲很短的字符串,或者所有值都接近同一個長度。例如,char類型非常適合存儲密碼的md5值,因為他是定長的值。還有用戶的身份證號以及手機號碼。對于經(jīng)常變更的數(shù)據(jù),char也比vachar更好,因為定長的char類型不容易產(chǎn)生碎片。對于非常短的列,char也比varchar在存儲空間上更有效率。例如用char(1)存儲Y和N的值,如果采用單字節(jié)字符集只需要一個字節(jié),但是varchar(1)卻需要兩個字節(jié),因為還有一個記錄長度的額外字節(jié)。
Varchar(5)和varchar(200)存儲‘hello’時空間開銷是一樣的,但是Varchar(5)會有很大的優(yōu)勢,因為更長的列會消耗更多的內(nèi)存,因為Mysql通常會分配固定帶下的內(nèi)存塊來保存內(nèi)部值。尤其是使用內(nèi)存臨時表進行排序和操作時會特別糟糕。在利用磁盤臨時表進行排序時也同樣糟糕。
時間類型
DateTime和TimeStamp
- DateTime
這個類型能保存大范圍的值,從1001年到9999年,精度為秒。它把日期和時間封裝到格式為YYYYMMDDHHMMSS的整數(shù)里,與時區(qū)無關(guān)。使用8個字節(jié)的存儲空間。
- TimeStamp:
存儲1970年1月1日午夜以來的描述,他和Unix時間戳相同。TimeStamp只使用4個字節(jié)的存儲空間,因此它的范圍比DateTime小的多;只能表示從1970年到2038年。
TimeStamp顯示的值也依賴于時區(qū)。Mysql服務(wù)器,操作系統(tǒng),以及客戶端連接都有時區(qū)設(shè)置。
TimeStamp也有DATETIME沒有的特殊屬性。默認情況下,如果插入時沒有指定第一個TimeStamp列的值,Mysql會設(shè)置這個列的值為當(dāng)前時間。在插入一行記錄時,Mysql默認也會更新第一個TimeStamp列的插入和更新操作。最后,TimeStamp列默認為not null,這也和其他的數(shù)據(jù)類型不一樣。