- 所有的資料庫物件名稱必須使用小寫字母並用下劃線分割(MySQL大小寫敏感,名稱要見名知意,最好不超過32字元)
- 所有的資料庫物件名稱禁止使用MySQL保留關鍵字(如 desc、range、match、delayed 等,請參考 MySQL官方保留字 )
- 臨時庫表必須以tmp為字首並以日期為字尾(tmp_)
- 備份庫和庫必須以bak為字首並以日期為字尾(bak_)
- 所有儲存相同資料的列名和列型別必須一致。(在多個表中的欄位如user_id,它們型別必須一致)
- mysql5.5之前預設的儲存的引擎是myisam,沒有特殊要求,所有的表必須使用innodb(innodb好處支援失誤,行級鎖,高併發下效能更好,對多核,大記憶體,ssd等硬體支援更好)
- 資料庫和表的字符集儘量統一使用utf8(字符集必須統一,避免由於字符集轉換產生的亂碼,漢字utf8下佔3個位元組)
- 所有表和欄位都要新增註釋COMMENT,從一開始就進行資料字典的維護
- 儘量控制單表資料量的大小在500w以內,超過500w可以使用歷史資料歸檔,分庫分表來實現(500萬行並不是MySQL資料庫的限制。過大對於修改表結構,備份,恢復都會有很大問題。MySQL沒有對儲存有限制,取決於儲存設定和檔案系統)
- 謹慎使用mysql分割槽表(分割槽表在物理上表現為多個檔案,在邏輯上表現為一個表)
- 謹慎選擇分割槽鍵,跨分割槽查詢效率可能更低
- 建議使用物理分表的方式管理大資料
- 儘量做到冷熱資料分離,減小表的寬度(mysql限制最多儲存4096列,行數沒有限制,但是每一行的位元組總數不能超過65535。列限制好處:減少磁碟io,保證熱資料的記憶體快取命中率,避免讀入無用的冷資料)
- 禁止在表中建立預留欄位(無法確認儲存的資料型別,對預留欄位型別進行修改,會對錶進行鎖定)
- 禁止在資料中儲存圖片,檔案二進位制資料(使用檔案伺服器)
- 禁止線上上做資料庫壓力測試
- 禁止從開發環境,測試環境直接連生產環境資料庫
- 限制每張表上的索引數量,建議單表索引不超過5個(索引會增加查詢效率,但是會降低插入和更新的速度)
- 避免建立冗餘索引和重複索引(冗餘:index(a,b,c) index(a,b) index(a))
- 禁止給表中的每一列都建立單獨的索引
- 每個innodb表必須有一個主鍵,選擇自增id(不能使用更新頻繁的列作為主鍵,不適用UUID,MD5,HASH,字串列作為主鍵)
- 區分度最高的列放在聯合索引的最左側
- 儘量把欄位長度小的列放在聯合索引的最左側
- 儘量避免使用外來鍵(禁止使用物理外來鍵,建議使用邏輯外來鍵)
- 優先選擇符合儲存需要的最小資料型別
- 優先使用無符號的整形來儲存
- 優先選擇儲存最小的資料型別(varchar(N),N代表的是字元數,而不是位元組數,N代表能儲存多少個漢字)
- 避免使用Text或是Blob型別
- 避免使用ENUM資料型別(修改ENUM值需要使用ALTER語句,ENUM型別的ORDER BY操作效率低,需要額外操作,禁止使用書值作為ENUM的列舉值
- 儘量把所有的欄位定義為NOT NULL(索引NULL需要額外的空間來儲存,所以需要暫用更多的記憶體,進行比較和計算要對NULL值做特別的處理)
- 使用timestamp或datetime型別來儲存時間
- 同財務相關的金額資料,採用decimal型別(不丟失精度,禁止使用 float 和 double)
- 避免使用雙%號和like,搜尋嚴禁左模糊或者全模糊(如果需要請用搜尋引擎來解決。索引檔案具有 B-Tree 的最左字首匹配特性,如果左邊的值未確定,那麼無法使用此索)
- 建議使用預編譯語句進行資料庫操作
- 禁止跨庫查詢(為資料遷移和分庫分表留出餘地,降低耦合度,降低風險)
- 禁止select * 查詢(消耗更多的cpu和io及網路頻寬資源,無法使用覆蓋索引)
- 禁止使用不含欄位列表的insert語句(不允許insert into t values(‘a’,‘b’,‘c’)不允許)
- in 操作能避免則避免,若實在避免不了,需要仔細評估 in 後邊的集合元素數量,控制在 1000 個之內
- 禁止使用order by rand()進行隨機排序
- 禁止where從句中對列進行函式轉換和計算(例如:where date(createtime)=‘20160901’ 會無法使用createtime列上索引。改成 where createtime>='20160901' and createtime <'20160902')
- 儘量使用 union all 代替 union
- 拆分複雜的大SQL為多個小SQL( MySQL一個SQL只能使用一個CPU進行計算)
- 儘量避免使用子查詢,可以把子查詢優化為join操作(子查詢的結果集無法使用索引,子查詢會產生臨時表操作,如果子查詢資料量大會影響效率,消耗過多的CPU及IO資源)
- 超過100萬行的批量寫操作,要分批多次進行操作(大批量操作可能會造成嚴重的主從延遲,binlog日誌為row格式會產生大量的日誌,避免產生大事務操作)
- 對於大表使用pt—online-schema-change修改表結構(避免大表修改產生的主從延遲,避免在對錶欄位進行修改時進行鎖表)
- 對於程式連線資料庫賬號,遵循許可權最小原則
- 超過三個表禁止 join。(需要 join 的欄位,資料型別必須絕對一致;多表關聯查詢時,保證被關聯的欄位需要有索引。即使雙表 join 也要注意表索引、SQL 效能。)
- 在varchar欄位上建立索引時,必須指定索引長度,沒必要對全欄位建立索引,根據實際文字區分度決定索引長度即可。
- SQL 效能優化的目標:至少要達到 range 級別,要求是 ref 級別,如果可以是 consts最好
- 使用 ISNULL()來判斷是否為 NULL 值。
- 儘量不要使用物理刪除(即直接刪除,如果要刪除的話提前做好備份),而是使用邏輯刪除,使用欄位delete_flag做邏輯刪除,型別為tinyint,0表示未刪除,1表示已刪除
- 如果有 order by 的場景,請注意利用索引的有序性。order by 最後的欄位是組合,索引的一部分,並且放在索引組合順序的最後,避免出現 file_sort 的情況,影響查詢效能。
- 在程式碼中寫分頁查詢邏輯時,若 count 為 0 應直接返回,避免執行後面的分頁語句
參考:
- 《阿里巴巴Java開發手冊》
- 《高效能可擴充套件MySQL資料庫設計及架構優化 電商專案》
歡迎大家指出更正和補充!