整數(shù)類型:
TINYINT,SWALLINT, MEDIUMINT,INT,BIGINT. 分別是 8,16,24,32,64 位儲存空間隐岛。
整數(shù)型有 UNSIGNED 屬性猫妙,例如 TINYINT. UNSIGNRD 可以儲存的范圍是 0~255,TINYINT 儲存范圍是 -128~127. 儲存的空間是相同的聚凹。
使用最適合的類型吐咳。
實數(shù)類型:
FLOAT逻悠,DOUBLE元践,DECIMAL. 都可以指定精度韭脊,例如 DECIMAL(18,9) 小數(shù)兩邊各存儲9個數(shù)字,一共9個字節(jié)单旁,小數(shù)點前用 4 個字節(jié)沪羔,小數(shù)點后 4 個,小數(shù)點占一個象浑。
DECIMAL 允許最多 64 個數(shù)字蔫饰。計算的時候會轉(zhuǎn)換為 DOUNBLE 類型。
FLOAT 使用 4 個字節(jié)存儲愉豺。DOUBLE 占用 8 個字節(jié)篓吁。
盡量只在對小數(shù)進行精確計算的時候才使用 DECIMAL。在數(shù)據(jù)量比較大的時候蚪拦,可以考慮使用 BIGINT 代替 DECIMAL杖剪。
字符串類型
VARCHAR 和 CHAR 是主要的字符串類型。
VARCHAR 類型用于儲存可變長字符串驰贷,需要使用 1 或者 2 個額外字節(jié)記錄長度盛嘿,小于等于 255 字節(jié)用一個,大于用兩個括袒。字符串列的最大長度比平均長度大很多次兆;列的更新少,所以碎片不是問題锹锰;使用了像 UTF-8 這樣復(fù)雜的字符集芥炭,每個字符都使用不同的字節(jié)數(shù)存儲。
CHAR是定長的恃慧,適合存儲比較短的字符串园蝠,或者所有值都接近一個長度。非常短的列糕伐,單字符集砰琢。
與 CHAR 和 VARCHAR 類似的類型還有 BINARY 和 VARBINARY。它們儲存的是二進制字符串良瞧,它的儲存是字節(jié)碼不是字符陪汽,填充是 \0 不是空格。優(yōu)勢是大小寫敏感褥蚯,比較式每次按一個字節(jié)挚冤,比較快。
BLOB 和 TEXT 是為了存儲很大的數(shù)據(jù)而設(shè)計的字符串類型赞庶。
字符類型 TINTTEXT训挡,SMALLTEXT澳骤,TEXT,MEDIUNTEXT澜薄,LONGTEXT为肮;二進制類型 TINYBLOB,SMALLBLOB肤京,BLOB颊艳,MEDIUMBLOB,LONGNBLOB忘分。
BLOB 和 TEXT值太大的時候棋枕,InnoDB 會使用專門的“外部”存儲區(qū)來進行存儲,此時每個值在行內(nèi)需要 1~4 個字節(jié)存儲一個指針妒峦,外部存儲實際的值重斑。
BLOB 和 TEXT之間僅有的不同是 BLOB 是二進制數(shù)據(jù),沒有排序柜子或字符集肯骇,而 TEXT 類型有字符集和排序規(guī)則窥浪。
使用枚舉代替字符串類型
枚舉不好的地方是:字符串列表是固定的,添加刪除字符串必須使用 ALTER TABLE累盗。 對于一系列未來可能會改變的字符串寒矿,使用枚舉不是好主意。
日期和時間類型
DATATIME
從 1001 到 9999年 精度為秒若债。YYYYMMDDHHMMSS
TIMESTAMP
1970到2038年 只使用 4 個字節(jié)符相。
盡量使用 TIMESTAMP。
位數(shù)據(jù)類型
BIT
可以使用 BIT 列在一列中存儲一個或者多個 true/false 值蠢琳。最大長度是 64 個位啊终。當檢索 BIT(1)的時候,結(jié)果是一個包含二進制 0 或 1 值的字符串傲须,而不是 ASCII 碼的 “0” “1”蓝牲。然而在數(shù)字上下文場景的時候結(jié)果是將位字符串轉(zhuǎn)換為數(shù)字。
SET
如果要保存很多的 true/false 可以考慮合并這些列到一個 SET 泰讽。主要缺點例衍,改變列的定義需要 ALTER TABLE。一般也無法在 SET 列上通過索引查找已卸。
一種替代方式,使用一個整數(shù)包裝一系列的位佛玄。每一位代表一個 0/1。
選擇標識符
為標識列選擇合適的數(shù)據(jù)類型非常重要累澡,一般來說跟更有可能用標識列與其他值進行比較梦抢,標識列可能在另外的表作為外鍵使用,所以為標識列選擇數(shù)據(jù)類型的時候愧哟,應(yīng)該選擇跟關(guān)聯(lián)表中的對應(yīng)列一樣的類型奥吩。
整數(shù)通常是最好的選擇哼蛆,ENUM SET適合存儲固定信息,避免使用字符串類型霞赫。因為一些 SELECT 語句變的很慢腮介。
特殊類型數(shù)據(jù)
例如 IPv4 地址,經(jīng)常用 VARCHAR(15) 來儲存 IP 地址绩脆。是 32 位無符號整數(shù)萤厅,用小數(shù)點分為四段方便閱讀。不是字符串靴迫,MySQL 提供 INET_ATON() 和 INET_NTOA()函數(shù)在這兩種表示方法之間轉(zhuǎn)換。
MySQL schema 設(shè)計中的陷阱
太多的列
MySQL 的儲存引擎 API 工作時需要在服務(wù)器和儲存引擎之間通過行緩存格式拷貝數(shù)據(jù)楼誓,然后在服務(wù)器層將緩沖內(nèi)容解碼成各個列玉锌。說白了列越多轉(zhuǎn)換代價就會非常高。
太多的關(guān)聯(lián)
實體-屬性-值(EVA) 是常見的糟糕的設(shè)計模式疟羹,MySQL限制了每個關(guān)聯(lián)操作最多只能有61張表主守,EVA 需要許多自關(guān)聯(lián)。經(jīng)驗告訴我們榄融,單個查詢最好在12個表以內(nèi)做關(guān)聯(lián)参淫。
全能的枚舉
防止過度使用枚舉,如果枚舉值過多愧杯,應(yīng)當用整數(shù)作為外鍵關(guān)聯(lián)到字典表或者查找表來查找具體值涎才。
但是每增加一個枚舉值有需要 ALTER TABLE。
范式的優(yōu)點和缺點
范式化的更新操作通常比反范式化要快力九。
當數(shù)據(jù)較好地范式化時耍铜,就只有很少沒有重復(fù)的數(shù)據(jù),所以只需要修改更少的數(shù)據(jù)跌前。
范式化的表通常更小棕兼,可以更好的放在內(nèi)存里,所以執(zhí)行操作會更快抵乓。
很少有多余的數(shù)據(jù)意味著檢索列表數(shù)據(jù)時更少需要 DISTINCT 或者 GROUP BY 語句伴挚。
缺點是通常需要關(guān)聯(lián)。
反范式的優(yōu)點和缺點
很好地避免了關(guān)聯(lián)灾炭。
在實際應(yīng)用當中都是混用范式化和反范式化的茎芋。
最常見的反范式化的數(shù)據(jù)方法是復(fù)制或者緩存,在不同的表中存儲相同的特定列咆贬,可以使用觸發(fā)器更新緩存值败徊。
網(wǎng)站實例中,可以再 user 和 message 中都儲存 account_type 字段掏缎,避免了完全反范式化的插入和刪除問題皱蹦,不會吧 user_message 表搞的太大煤杀,有利于高效的獲取數(shù)據(jù)。但是更新用戶的賬戶類型操作代價就高了沪哺,這需要考慮更新的頻率以及更新的時長沈自,并和執(zhí)行 SELECT 查詢的頻率進行比較。
如果需要顯示每個用戶發(fā)了多少消息辜妓,可以再 user 表中建一個 num_message 列枯途,每當用戶發(fā)消息就更新這個表。
緩存表和匯總表
有時提升性能最好的方法是在同一張表中保存衍生冗余數(shù)據(jù)籍滴,有時也需要創(chuàng)建一張完全獨立的匯總表和緩存表酪夷。
緩存表儲存那些可以比較簡單地從 schema 其他表(但每次獲取的速度比較慢)數(shù)據(jù)的表
匯總表保存的是使用 GROUP BY 語句聚合數(shù)據(jù)的表。 緩存表對優(yōu)化搜索和檢索查詢語句很有效孽惰。
當重建匯總表和緩存表示需要一個影子表晚岭。
加快 ALTER TABLE 操作的速度
對于常見的場景,只有兩種:一是先在一臺不提供服務(wù)的機器上執(zhí)行 ALTER TALBLE 操作勋功,然后和提供服務(wù)的主庫進行切換坦报。另一種是,影子拷貝狂鞋,是用要求的表結(jié)構(gòu)創(chuàng)建一張和源表不管的新表片择,然后通過重命名和刪除操作叫喚兩張表。
一些場景中骚揍,可以通過 ALTER COLUMN 操作來改變列的值字管,這樣只會修改.frm文件。