命名規範
> 庫名、表名、字段名必須使用小寫字母並採用下劃線分割
> 庫名、表名、字段名禁止超過32個字符,須見名知意
* 庫名、表名、字段名支持最多64個字符,統一規範、易於辨識以及減少傳輸量不要超過32
> 庫名、表名、字段名禁止使用MySQL保留關鍵字
> 臨時庫、臨時表名必須以tmp爲前綴並以日期爲後綴
> 備份庫、備份表名必須以bak爲前綴並以日期爲後綴
基本規範
> 使用INNODB存儲引擎
* 5.5以後的默認引擘,支持事務,行級鎖,更好的恢復性,高併發下性能更好,對多核,大內存,ssd等硬件支持更好
> 表字符集使用UTF8
* 使用utf8字符集,如果是漢字,佔3個字節,但ASCII碼字符還是1個字節
* 統一,不會有轉換產生亂碼風險
> 所有表都需要添加註釋
> 單表數據量建議控制在5000萬以內
> 不在數據庫中存儲圖片、文件等大數據
> 禁止在線上做數據庫壓力測試
> 禁止從測試、開發環境直連數據庫
庫表設計規範
> 禁止使用分區表
* MySQL的分區表實際性能不是很好,且管理維護成本較高
> 拆分大字段和訪問頻率低的字段,分離冷熱數據
> 用HASH進行散表,表名後綴使用十進制數,下標從0開始
* 首次分表儘量多的分,避免二次分表,二次分表的難度和成本較高
> 按日期時間分表需符合YYYY[MM][DD][HH]格式
> 採用合適的分庫分表策略,如千庫十個表、十庫百表等
索引設計規範
索引是一把雙刃劍,它可以提高查詢效率但也會降低插入和更新的速度並佔用磁盤空間
> 單張表中索引數量不超過5個
> 單個索引中的字段數不超過5個
> 對字符串使用前綴索引,前綴索引長度不超過10個字符
* 如果有一個CHAR(200) 列,如果在前10個字符內,多數值是惟一的,那麼就不要對整個列進行索引。對前10 個字符進行索引能夠節省大量索引空間,也可能會使查詢更快
> 表必須有主鍵
> 不使用更新頻繁地列作爲主鍵
> 儘量不選擇字符串列作爲主鍵
> 不使用UUID、MD5、HASH 作爲主鍵
> 默認使用非空的唯一鍵
> 主鍵建議選擇自增或發號器
> 重要的SQL必須被索引
* SELECT、UPDATE、DELETE語句的WHERE條件列
* ORDER BY、GROUP BY、DISTINCT的字段
* 多表JOIN的字段
> 區分度最大的字段放在索引前面
> 核心SQL優先考慮覆蓋索引
* select的數據列只用從索引中就能夠取得,不必讀取數據行,換句話說查詢列要被所建的索引覆蓋
> 避免冗餘或重複索引
* 合理創建聯合索引(避免冗餘),index(a,b,c) 相當於 index(a) 、index(a,b) 、index(a,b,c)
> 索引不是越多越好,按實際需要進行創建
* 每個額外的索引都要佔用額外的磁盤空間,並降低寫操作的性能
> 不在低基數列上建立索引,例如‘性別’
> 不在索引列進行數學運算和函數運算
> 儘量不要使用外鍵
* 外鍵用來保護參照完整性,可在業務端實現
* 對父表和子表的操作會相互影響,降低可用性
* INNODB本身對Online DDL的限制
> 不使用%前導的查詢,如like “%xxx”
* 無法使用索引
> 不使用反向查詢,如 not in / not like
* 無法使用索引,導致全表掃描
* 全表掃描導致buffer pool利用降低
字段設計規範
> 儘可能不要使用TEXT、BLOB類型
* 刪除這種值會在數據表中留下很大的"空洞"
* 可以考慮把BLOB或TEXT列分離到單獨的表中
> 用DECIMAL代替FLOAT和DOUBLE存儲精確浮點數
* 浮點數相對於定點數的優點是在長度一定的情況下,浮點數能夠表示更大的數據範圍
浮點數的缺點是會引起精度問題
> 將字符轉化爲數字
> 使用TINYINT來代替ENUM類型
> 字段長度儘量按實際需要進行分配,不要隨意分配一個很大的容量
* the best strategy is to allocate only as much space as you really need
* VARCHAR(N),N表示的是字符數不是字節數,比如VARCHAR(255),可以最大可存儲255個漢字,需要根據實際的寬度來選擇N
* VARCHAR(N),N儘可能小,因爲MySQL一個表中所有的VARCHAR字段最大長度是65535個字節,進行排序和創建臨時表一類的內存操作時,會使用N的長度申請內存
> 如果可能的話所有字段均定義爲not null
> 使用UNSIGNED存儲非負整數
* 同樣的字節數,存儲的數值範圍更大。如tinyint 有符號爲 -128-127,無符號爲0-255
> INT類型固定佔用4個字節存儲
> 使用TIMESTAMP存儲時間
* 因爲TIMESTAMP使用4字節,DATETIME使用8個字節, 同時TIMESTAMP具有自動賦值以及自動更新的特性
> 使用INT UNSIGNED 存儲IPV4
> 使用VARBINARY存儲大小寫敏感的變長字符串
> 禁止在數據庫中存儲明文密碼
SQL設計規範
> 使用預編譯語句prepared statement
* 只傳參數,比傳遞SQL語句更高效
* 一次解析,多次使用
* 降低SQL注入概率
java 方法如下: protected boolean updateSalary(Connection conn,BigDecimal x,String ID) throws SQLException{ PreparedStatement pstmt = null; try { pstmt = conn.prepareStatement("UPDATE EMPLOYEES SET SALARY = ? WHERE ID = ?"); pstmt.setBigDecimal(1, x); pstmt.setString(2, ID); return true; } finally{ if (pstmt!=null){ pstmt.close(); } }
}
> 儘量避免相同語句由於書寫格式的不同,而導致多次語法分析
> 避免隱式轉換
* 會導致索引失效,如 select userid from table where userid=’1234’
> 充分利用前綴索引
* 必須是最左前綴
* 不可能同時用到兩個範圍條件
> 避免使用存儲過程、觸發器、EVENTS等
* 讓數據庫做最擅長的事
* 降低業務耦合度,爲Scale Out、Sharding 留點餘地
* 避開BUG
> 避免使用大表的join
* MySQL最擅長的是單表的主鍵/二級索引查詢
* Join消耗較多的內存,產生臨時表
> 避免在數據庫中進行數學運算
* 容易將業務邏輯和DB耦合在一起
* MySQL不擅長數學運算和邏輯判斷
* 無法使用索引
> 減少與數據庫的交互次數
* Insert … on duplicate key update
* Replace into 、 insert ignore、insert into values(),(),()…
* Update … where id in (1,2,3,4)
* Alter table tbl_name add column col1, add column col2
> 拒絕大SQL,拆分成小SQL
* 充分利用query cache
* 充分利用多核CPU
> 使用in代替or,in的值不超過1000個
> 禁止使用order by rand()
* 因爲ORDER BY rand()會將數據從磁盤中讀取,進行排序,會消耗大量的IO和CPU,可以在程序中獲取一個rand
值,然後通過在從數據庫中獲取對應的值
> 使用union all 而不是union
> 程序應有捕獲SQL異常的處理機制
> 禁止單條SQL語句同時更新多個表
> 不使用select *
* 消耗cpu和IO、消耗網絡帶寬
* 無法使用覆蓋索引
* 減少表結構變更帶來的影響
行爲規範
> 批量導入、導出數據必須提前通知DBA協助觀察
> 批量更新數據,如update,delete 操作,需要DBA進行審查,並在執行過程中觀察服務
> 禁止在從庫上執行後臺管理和統計類的功能查詢
> 禁止有super權限的應用程序賬號存在
> 產品出現非數據庫導致的故障時及時通知DBA協助排查
> 促銷活動或上線新功能必須提前通知DBA進行流量評估
> 數據庫數據丟失,及時聯繫DBA進行恢復
> 對單表的多次alter操作必須合併爲一次操作
> 不在MySQL數據庫中存放業務邏輯
> 重大項目的數據庫方案選型和設計必須提前通知DBA參與
> 對特別重要的庫表,提前與DBA溝通確定維護和備份優先級
> 不在業務高峯期批量更新、查詢數據庫
> 提交線上建表需求,必須詳細註明所有相關SQL