前言
這是來自一線的實戰(zhàn)經驗眨补,每一條軍規(guī)背后都是血淋淋的教訓。
核心篇
-
不在數據庫做運算
存儲過程倒脓、函數撑螺、觸發(fā)器、試圖崎弃、級聯刪除等數據庫功能嚴禁使用甘晤。數據庫是用來存取數據的含潘,而不是做業(yè)務處理的。數據庫做集群的代價遠遠大于應用服務器线婚。在當前這個互聯網時代中軟件所需要處理的數據越來越多遏弱,請珍惜數據庫的資源。 -
控制單表數據量
一年內單表數據量不要超過500W(隨著硬件性能提升而提升)塞弊;單庫不超過50張表腾窝,推薦ER圖不超過一屏幕,一目了然可以大大提高對數據庫結構的理解居砖。 -
控制單表字段數上限在20~50
字段少的好處多多:IO高效、全表遍歷快驴娃、表修復快奏候、alter table 快、提高開發(fā)效率 -
平衡范式與冗余
本庫在沒有性能瓶頸的情況下不考慮冗余唇敞≌岵荩跨庫關鍵字段必須冗余,實時類數據要保證最終一致性疆柔,(在業(yè)務判斷影響不大的情況下也可以不同步)當出現頻繁的同步需求時咒精,往往是庫的拆分出問題了,應該考慮調整數據庫設計旷档。歷史類數據不叫冗余那是尊重歷史模叙,如訂單中的客戶名稱、貨品名稱等鞋屈。 -
拒絕3B
大SQL范咨、大事務、大批量
字段篇
-
用好數值字段類型
在夠用的情況下盡量選擇字節(jié)數少的類型厂庇。
tinyint(1B)渠啊、smallint(2B)、mediumint(3B)权旷、int(4B)替蛉、bigint(8B)
float(4B)、double(8)
decimal(m拄氯,d) -
能用數字不用字符串
數字更高效躲查、查詢更快(經驗值是20%)、占用空間更小坤邪。 -
避免使用null值
在mysql中無法對null進行查詢優(yōu)化熙含,有null值的列加索引需要額外空間,含null的復合索引無效艇纺。設計合理的默認值可以規(guī)避null的問題怎静,例如 varchar用 emptystring 邮弹,數字用0等等。 -
禁止使用text/blob/clob等大字段
這些大字段會強制生成硬盤臨時表蚓聘,浪費空間腌乡。在業(yè)務需要存儲較大內容時,請使用文件服務器存儲夜牡,在數據庫中存儲其url地址与纽。 -
不在數據庫里存圖片
原理同上。
索引篇
-
謹慎合理添加索引
索引可以提高查詢的性能塘装,但會減慢更新的速度急迂。所以并不是越多越好,控制在字段數的20%以內蹦肴。 -
字符字段必須建前綴索引
將整個字符串都加入到索引中僚碎,是十分浪費空間的。其實用前若干位已經可以達到很好的效果了阴幌,實際用多少位需要根據實際場景判定勺阐。這個給大家?guī)讉€數字作為參考
單字母區(qū)分度:26(字母,不考慮大小寫)+ 10(數字)= 36(理論值是255矛双,這里我們只考慮常見的)
4字母區(qū)分度:36 × 36 × 36 × 36 = 1,679,616(1百多萬)
5字母區(qū)分度:36 × 36 × 36 × 36 × 36 = 60,466,176(6千萬)
6字母區(qū)分度:36 × 36 × 36 × 36 × 36 × 36 = 2,176,782,336(20億) -
不在索引列做運算
索引失效渊抽。其實所有列的運算都不推薦,運算應該交給java议忽。 -
主鍵使用bigint且自增
忌用字符串做主鍵懒闷。 -
禁止使用外鍵
高并發(fā)時容易死鎖。使用程序保證約束栈幸。
Sql篇
-
盡可能簡單
將一條大sql拆成幾條小sql執(zhí)行毛雇。一條大sql可能把整個數據庫堵死。簡單sql緩存命中率更高侦镇、減少鎖表時間灵疮,用上多cpu(一條sql只能在一個cpu運算)。 -
保持事務(鏈接)短小
事務使用原則:即開即用壳繁,用完即關
與事務無關操作放到事務外面震捣,減少鎖資源的占用
不破壞一致性前提下,使用多個短事務代替長事務 -
禁止使用
select *
只取需要數據列闹炉,減少傳輸量蒿赢,減少表變化帶來的影響。join時同名列會自動添加后綴影響程序的取數渣触。 -
用union all 而非 union
union 的結果是去重的羡棵,這個消耗很大。 -
改寫or為in()
or的效率為 O(n)嗅钻,in的效率為O(Log n)當n很大時皂冰,or會慢很多店展。即便如此也要控制in的個數,建議n小于200秃流。 -
改寫or為union
前面的是一個字段多個值的場景赂蕴,這個是不同字段的場景。注意:這里不能使用union all舶胀。 -
避免非邏輯查詢和%前綴模糊查詢
非邏輯指 not概说、!=、<>嚣伐、!<糖赔、!>、not exists轩端、not in挂捻、not like等。%前綴模糊查詢 使用不了索引船万,導致全表掃描。 -
同數據類型的列值比較
數字對數字骨田,字符對字符耿导。浮點型不推薦比較。主外鍵必須使用同數據類型(通常是bigint)态贤。不同類型的字段比較時舱呻,會消耗類型轉換的運算量,并且容易導致索引失效悠汽。 -
禁止單詞請求中大批量更新
容易出現大事務箱吕。在設計層面規(guī)避,無法避免時請使用隊列控制數據庫的壓力柿冲。 -
explain
使用explain優(yōu)化sql語句是每個程序員都應該學會的茬高。開發(fā)庫往往比生成庫少很多的數據,一條未經優(yōu)化的sql上線假抄,可能導致一場災難怎栽。
約定篇
- 隔離線上線下
-
禁止使用子查詢
大部分情況很難優(yōu)化。in 通常是可以改寫為join的宿饱。 -
禁止在程序端顯示加鎖
外部鎖對數據庫不可控熏瞄。高并發(fā)時是災難。極難調試和排查谬以。 -
統一字符集為UTF-8
校對規(guī)則 utf8_general_ci -
統一命名規(guī)范
庫强饮、表、字段統一使用小寫为黎,單詞之間使用下劃線分隔邮丰。
主鍵:表名關鍵字id
索引:idx字段名(復合組件則用多個字段名行您,過長時使用縮寫)
避免使用保留字:如 desc 描述的縮寫 結果是 排序的關鍵字。 -
必備字段
每張實體表都需要記錄以下字段柠座,并置于字段最后面
create_time
create_user_id
create_user_name
modify_time
modify_user_id
modify_user_name
插入時modify的值同create
關聯表不需要記錄
固定數據的基礎資料不需要記錄 -
日期類型統一使用 timestamp
國際物流是有時區(qū)問題的邑雅。 -
字段順序
設計表結構時需要按照重要程度自上而下排列,在添加字段時必須嚴格遵守妈经,不能簡單的加載最后面淮野。相關的字段必須排在一起,例如user_id吹泡、user_name骤星。 -
可事先約定且有限值的字段使用varchar
雖然常見的做法是int或tinyint,但是在意義表達上不如字符串來的清晰爆哑,為了更加便于維護洞难,