第四章
選擇數(shù)據(jù)類型甩挫,幾個簡單的原則:
- 更小的通常更好
- 簡單就好吁断,比如使用MySQL內(nèi)建datetime、timestamp槐壳,不使用字符串存儲時間然低。使用整數(shù)存儲IP地址
SELECT INET_ATON('192.168.1.212'), INET_NTOA(3232235988)
。 - 盡量避免NULL
摘要
- 當數(shù)據(jù)量比較大時候,可以考慮使用BIGINT代替DECIMAL雳攘,將存儲的貨幣單位根據(jù)小數(shù)位數(shù)乘以相應(yīng)倍數(shù)带兜。
- varchar 需要1或者2個額外字節(jié)存儲字符串的長度,如果列的最大長度<=255字節(jié)吨灭,需要1個字節(jié)刚照,否則2個字節(jié)。另外喧兄,varchar變長當更新時候无畔,有可能會導致分裂頁進行存儲。Innodb會把過長的varchar存儲為BLOB吠冤。
- 下面情況適用varchar合適的: 字符串最大長度比平均長度大很多浑彰;列更新很少,所以碎片不是問題拯辙;使用了UTF-8復(fù)雜字符集郭变,每個字符串使用不同的字符數(shù)存儲。
- varchar(255)涯保,定義的不是字節(jié)數(shù)诉濒,是字符數(shù)。
- char(3)如果采用單字節(jié)字符集夕春,存儲需要3個字節(jié)未荒。而varchar(3),需要4個字節(jié)
- varchar(5)和varchar(200)存儲 'hello'的空間開銷是一樣的撇他,那么使用更短列有什么優(yōu)勢呢茄猫?事實證明有很大優(yōu)勢。更大的列會消耗更多的存儲困肩。因為MySQL通用會分配固定大小的內(nèi)存塊來保存內(nèi)部值划纽。尤其是使用內(nèi)存臨時表進行排序或操作時特別糟糕,在利用磁盤臨時表也同樣糟糕锌畸。
- 不使用ENUM類型勇劣,如COLOR,現(xiàn)在要加一個YELLOW枚舉潭枣,需要Alter table比默。如果改變原始枚舉值,比如把WHITE變?yōu)镽ED盆犁,存儲變?yōu)?'空字符串命咐。
選擇標示列類型
標示列,一般是主鍵或者關(guān)聯(lián)列谐岁。
- 整數(shù)是標識列列的最后選擇醋奠,很快并且可以Auto_increment
- 如果可以避免使用字符串作為標示列榛臼,很消耗空間并且比數(shù)字慢。最多有6倍的性能下降窜司。insert語句使用字符串做主鍵可能會導致頁分裂沛善、磁盤隨機訪問,innodb還會導致聚簇索引碎片塞祈。如果一定要使用UUID金刁,應(yīng)該移除-,使用UNHex函數(shù)轉(zhuǎn)換為16字節(jié)數(shù)字议薪,并存儲在BINARY(16)[blob]列尤蛮,檢索是通過HEX函數(shù)來格式為十六進制。所以還是推薦使用整數(shù)笙蒙。
范式和反范式
反范式是值schema把數(shù)據(jù)都放一張表里,可以很好避免關(guān)聯(lián)
計數(shù)器表的優(yōu)化
如果有一張表CREATE TABLE hit_counter(cnt int unsigned not null)
記錄點擊次數(shù)捅位,每次更新這行數(shù)據(jù)事務(wù)來說轧葛,都有一個全局的互斥鎖mutex。要獲得更高性能可以采用分治思想尿扯,把熱點行數(shù)據(jù)分拆。
CREATE TABLE hit_counter( slot tinyint unsigned not null primary key,
cnt int unsigned not null);
insert INTO hit_counter(slot, cnt) VALUE (RAND() * 100, 1)
ON DUPLICATE KEY UPDATE cnt = cnt + 1;