一、基礎規范:
1. 必須使用InnoDB存儲引擎
解讀:支持事務、行級鎖、並發性能更好、CPU及內存緩存頁優化使得資源利用率更高
2. 新庫默認使用utf8mb4字符集
解讀:utf8mb4是utf8的超集,emoji表情以及部分不常見漢字在utf8下會表現為亂碼,故需要升級至utf8mb4。
默認使用這個字符集的原因是:“標准,萬國碼,無需轉碼,無亂碼風險”,並不“節省空間”。
3. 數據表、數據字段必須加入中文注釋
解讀:N年后誰tm知道這個r1,r2,r3字段是干嘛的
4. 禁止使用存儲過程、視圖、觸發器、Event
解讀:高並發大數據的互聯網業務,架構設計思路是“解放數據庫CPU,將計算轉移到服務層”,並發量大的情況下,這些功能很可能將數據庫拖死,
業務邏輯放到服務層具備更好的擴展性,能夠輕易實現“增機器就加性能”。數據庫擅長存儲與索引,CPU計算還是上移吧
5. 禁止存儲大文件或者大照片
解讀:為何要讓數據庫做它不擅長的事情?大文件和照片存儲在文件系統,數據庫里存URI多好
6. 禁止使用應用程序配置文件內的帳號手工訪問線上數據庫
7. 禁止非DBA對線上數據庫進行寫操作,修改線上數據需要提交工單,由DBA執行,提交的SQL語句必須經過測試
8. 分配非DBA以只讀帳號,必須通過VPN+跳板機訪問授權的從庫
9. 開發、測試、線上環境隔離
10. 不在數據庫做計算,cpu計算務必移至業務層
11. 平衡范式與冗余,為提高效率可以犧牲范式設計,冗余數據
12. 拒絕3B(big),大sql,大事務,大批量
二、命名規范
1. 只允許使用內網域名,而不是ip連接數據庫
解讀:使用域名,在切換數據庫服務器的時候,只需要改DNS域名解析,不需要改配置文件。達到一處更改,多處生效的效果。
不只是數據庫,緩存(memcache、redis)的連接,服務(service)的連接都必須使用內網域名,機器遷移/平滑升級/運維管理…太多太多的好處,
如果朋友你還是采用ip直連的,趕緊升級到內網域名吧。
2. 線上環境、開發環境、測試環境數據庫內網域名遵循命名規范
業務名稱:xxx
線上環境:dj.xxx.db
開發環境:dj.xxx.rdb (r 是research, rd 是 research and development 的簡稱)
測試環境:dj.xxx.tdb
從庫在名稱后加-s標識,備庫在名稱后加-ss標識 (從庫,secondary database)
線上從庫:dj.xxx-s.db
線上備庫:dj.xxx-sss.db
3. 庫名、表名、字段名:小寫,下划線風格,不超過32個字符,必須見名知意,禁止拼音英文混用
4. 表名t_xxx,非唯一索引名idx_xxx,唯一索引名uniq_xxx (idx :索引文件(Index file))
三、表設計規范
1. 單實例表數目必須小於500
2. 單表列數目必須小於30
3. 表必須有主鍵,例如自增主鍵
解讀:
a)主鍵遞增,數據行寫入可以提高插入性能,可以避免page分裂,減少表碎片提升空間和內存的使用
b)主鍵要選擇較短的數據類型, Innodb引擎普通索引都會保存主鍵的值,較短的數據類型可以有效的減少索引的磁盤空間,提高索引的緩存效率
c) 無主鍵的表刪除,在row模式的主從架構,會導致備庫夯住
4. 禁止使用外鍵,如果有外鍵完整性約束,需要應用程序控制
解讀:外鍵會導致表與表之間耦合,update與delete操作都會涉及相關聯的表,十分影響sql 的性能,甚至會造成死鎖。高並發情況下容易造成數據庫性能,
大數據高並發業務場景數據庫使用以性能優先
5. 控制單表數據量,單表記錄控制在千萬級
四、字段設計規范
1. 必須把字段定義為NOT NULL並且提供默認值
解讀:
a)null的列使索引/索引統計/值比較都更加復雜,對MySQL來說更難優化
b)null 這種類型MySQL內部需要進行特殊處理,增加數據庫處理記錄的復雜性;同等條件下,表中有較多空字段的時候,數據庫的處理性能會降低很多
c)null值需要更多的存儲空間,無論是表還是索引中每行中的null的列都需要額外的空間來標識
d)對null 的處理時候,只能采用is null或is not null,而不能采用=、in、<、<>、!=、not in這些操作符號。如:where name!=’shenjian’,如果存在name
為null值的記錄,查詢結果就不會包含name為null值的記錄。(無論有無索引,都搜不到,已驗證)
2. 禁止使用TEXT、BLOB類型
解讀:會浪費更多的磁盤和內存空間,非必要的大量的大字段查詢會淘汰掉熱數據,導致內存命中率急劇降低,影響數據庫性能
3. 禁止使用小數存儲貨幣
解讀:使用整數吧,小數容易導致錢對不上
4. 必須使用varchar(20)存儲手機號
解讀:
a)涉及到區號或者國家代號,可能出現+-()
b)手機號會去做數學運算么?
c)varchar可以支持模糊查詢,例如:like“138%”
5. 禁止使用ENUM,可使用TINYINT代替
解讀:
a)增加新的ENUM值要做DDL操作
b)ENUM的內部實際存儲就是整數,你以為自己定義的是字符串?
6. 禁止使用小數存儲國幣
有朋友問存儲前乘以100,取出后除以100是否可行,個人建議“盡量少的使用除法”。
曾經踩過這樣的坑,100元分3天攤銷,每天攤銷100/3元,結果得到3個33.33。后來實施對賬系統,始終有幾分錢對不齊,郁悶了很久(不是幾分錢
的事,是業務方質疑的眼神讓研發很不爽),最后發現是除法惹的禍。
解決方案:使用“分”作為單位,這樣數據庫里就是整數了。
7. 字段選擇類型更小的通常更好:
解讀:更小的數據類型通常更快,因為他們占用更少的磁盤、內存和CPU緩存,並且處理需要的CPU周期也更少。
8. 簡單就好:
解讀:簡單的數據類型的操作通常需要更少的CPU周期。例如:整型比字符串操作的代價更低,因為字符集和校對規則(排序規則)是字符串比較比整型比較更復雜。
這里有兩個例子:一個是應該使用MySQL內建的類型而不是字符串來存儲日期和時間,另外一個是應該使用整型存儲IP地址。
9. 因為需要額外的空間和計算開銷,所以應該盡量只在對小數進行精確計算時才使用DECIMAL。在數據量比較大的時候,可以考慮使用BIGINT代替DECIMAL,
將對應的值擴大N倍。
10. 二進制比較的優勢並不僅僅體現在大小寫敏感上。MySQL比較BINARY字符串時,每次按一個字節,並且根據該字節的數值進行比較。因此,二進制比字符比較簡單
的多,所以也就更快。
11. 可以使用BIGINT類型存儲微秒級別的時間戳。
12. 一旦選擇了一種類型,要確保在所有關聯表中都使用同樣的類型。會用不同數據類型可能導致性能問題,即使沒有性能影響,在比較操作時隱式類型轉換也可能
導致很難發現錯誤。
13. 如果可能,應該避免使用字符串類型作為標識列,因為它們很消耗空間,並且通常比數字類型慢。
14. 范式(修改多,關聯查詢少)和反范式(查詢多,修改少)的選擇
15. 合理使用緩存表、匯總表、計數器表
五、索引設計規范
1. 單表索引建議控制在5個以內
2. 單索引字段數不允許超過5個
解讀:字段超過5個時,實際已經起不到有效過濾數據的作用了
3. 禁止在更新十分頻繁、區分度不高的屬性上建立索引
解讀:
a)更新會變更B+樹,更新頻繁的字段建立索引會大大降低數據庫性能
b)“性別”這種區分度不大的屬性,建立索引是沒有什么意義的,不能有效過濾數據,性能與全表掃描類似
4. 建立組合索引,必須把區分度高的字段放在前面
解讀:能夠更加有效的過濾數據
mysql筆記01 MySQL架構與歷史、Schema與數據類型優化
varchar(10) 和 varchar(100) 存儲5個字節的數據,是否一樣?
如現在用戶需要存儲一個地址信息。根據評估,只要使用100個字符就可以了。但是有些數據庫管理員會認為,反正Varchar數據類型是根據實際的需要來分配長度的。還不如給其大一點的呢。為此他們可能會為這個字段一次性分配200個字符的存儲空間。這VARCHAR(100)與VARCHAR(200)真的相同嗎?結果是否定的。雖然他們用來存儲90個字符的數據,其存儲空間相同。但是對於內存的消耗是不同的。對於VARCHAR數據類型來說,硬盤上的存儲空間雖然都是根據實際字符長度來分配存儲空間的,但是對於內存來說,則不是。內存使用固定大小的內存塊來保存值。簡單的說,就是使用字符類型中定義的長度,即200個字符空間。顯然,這對於排序或者臨時表(這些內容都需要通過內存來實現)作業會產生比較大的不利影響。解釋可以參見這里。所以如果某些字段會涉及到文件排序或者基於磁盤的臨時表時,分配VARCHAR數據類型時仍然不能夠太過於慷慨。還是要評估實際需要的長度,然后選擇一個最長的字段來設置字符長度。如果為了考慮冗余,可以留10%左右的字符長度。千萬不能認為其為根據實際長度來分配存儲空間,而隨意的分配長度,或者說干脆使用最大的字符長度。
1. 雖然用varchar(100)和varchar(10)儲存’abc’在硬盤上的大小一樣, 但是, 在內存里前者占100個字節, 后者只占10個字節. 對需要排序操作的字段, 不能分配varchar(100000)這樣的長度, 而是需要根據業務, 仔細定一個最大值.
2. 不能大於最大長度, 例如, varchar(1), 收到’abc’也會報錯
3. CHAR(1)與VARCHAR(1)兩這個定義,會有什么區別呢?雖然這兩個都只能夠用來保存單個的字符,但是VARCHAR要比CHAR多占用一個存儲位置。這主要是因為使用VARCHAR數據類型時,會多用1個字節用來存儲長度信息。這個管理上的開銷CHAR字符類型是沒有的。
4. 需要經常變化長度的字段使用char(20)比使用varchar(20)好, 這樣可以避免碎片和額外的調整工作。char(20)給字符串分配的空間就是20,而varchar分配的不一定是20,如果字符串更改,超過原來的長度,varchar可能需要額外的調整。
三是從碎片角度進行考慮。使用CHAR字符型時,由於存儲空間都是一次性分配的。為此某個字段的內容,其都是存儲在一起的。單從這個角度來講,其不存在碎片的困擾。而可變長度的字符數據類型,其存儲的長度是可變的。當其更改前后數據長度不一致時,就不可避免的會出現碎片的問題。故使用可變長度的字符型數據時,數據庫管理員要時不時的對碎片進行整理。如執行數據庫導出導入作業,來消除碎片。
參見:https://blog.csdn.net/imzoer/article/details/8435540/
http://tech.it168.com/a2011/0426/1183/000001183173.shtml#articlecomment