MySql 開發設計規範
1.杜絕直接 SELECT * 讀取全部欄位
即使需要所有欄位,減少網路頻寬消耗,能有效利用覆蓋索引,表結構變更對程式基本無影響
2.能確定返回結果只有一條時,使用 limit 1
在保證資料不會有誤的前提下,能確定結果集數量時,多使用limit,儘快的返回結果。
3.小心隱式型別轉換
轉換規則
a.兩個引數至少有一個是 NULL 時,比較的結果也是 NULL,例外是使用 <=> 對兩個 NULL 做比較時會返回 1,這兩種情況 都 不需要做型別轉換 b. 兩個引數都是字串,會按照字串來比較,不做型別轉換
4. 禁止在where
會導致索引失效,如lower(email),f_qq % 4。可放到右邊的常量上計算
返回小結果集不是很大的情況下,可以對返回列使用函式,簡化程式開發
5. 使用like模糊匹配,%不要放首位
會導致索引失效,有這種搜尋需求是,考慮其它方案,如sphinx全文搜尋
6. 涉及到複雜sql時,務必先參考已有索引設計,先explain
簡單SQL拆分,不以程式碼處理複雜為由。
比如 OR 條件: f_phone=’10000’ or f_mobile=’10000’,兩個欄位各自有索引,但只能用到其中一個。可以拆分成2個sql, 或者union all。
先
7. 使用join時,where條件儘量使用充分利用同一表上的索引
如 select t1.a,t2.b * from t1,t2 and t1.a=t2.a and t1.b=123 and t2.c= 4 ,如果t1.c與t2.c欄位相同,那麼t1上的索引(b,c)就 只用到b了。此時如果把where條件中的t2.c=4改成t1.c=4,那麼可以用到完整的索引
這種情況可能會在欄位冗餘設計(反正規化)時出現
正確選取inner join和left join
8. 少用子查詢,改用join
小於5.6版本時,子查詢效率很低,不像Oracle那樣先計運算元查詢後外層查詢。5.6版本開始得到優化
9. 考慮使用union all,少使用union,注意考慮去重
union all不去重,而少了排序操作,速度相對比union要快,如果沒有去重的需求,優先使用union all
如果UNION結果中有使用limit,在2個子SQL可能有許多返回值的情況下,各自加上limit。如果還有order by,請找DBA。
10. IN的內容儘量不超過200個
超過500個值使用批量的方式,否則一次執行會影響資料庫的併發能力,因為單SQL只能且一直佔用單CPU,而且可能導致 主從複製延遲
11. 拒絕大事務
比如在一個事務裡進行多個select,多個update,如果是高頻事務,會嚴重影響MySQL併發能力,因為事務持有的鎖等資源 只在事務rollback/commit時才能釋放。但同時也要權衡資料寫入的一致性。
12. 避免使用is null, is not null這樣的比較
13. order by .. limit
這種查詢更多的是通過索引去優化,但order by的欄位有講究,比如主鍵id與f_time都是順序遞增,那就可以考慮order by id 而非 f_time 。
14. c1 < a order by c2
與上面不同的是,order by之前有個範圍查詢,由前面的內容可知,用不到類似(c1,c2)的索引,但是可以利用(c2,c1)索引。 另外還可以改寫成join的方式實現。
15. 分頁優化
建議使用合理的分頁方式以提高分頁效率,大頁情況下不使用跳躍式分頁假如有類似下面分頁語句: SELECT FROM table1 ORDER BY ftime DESC LIMIT 10000,10; 這種分頁方式會導致大量的io,因為MySQL使用的是提前讀取策略。 推薦分頁方式: SELECT FROM table1 WHERE ftime < last_time ORDER BY ftime DESC LIMIT 10 即傳入上一次分頁的界值SELECT id FROM table ORDER BY time LIMIT 10000,10) as t2 ON t1.id=t2.id
16. count計數
1.首先count()、count(1)、count(col1)是有區別的,count()表示整個結果集有多少條記錄,count(1)表示結果集裡 以 primary key統計數量,絕大多數情況下count()與count(1)效果一樣的,但count(col1)表示的是結果集裡 col1 列 NOT null 的記錄數。優先採用count()
2.大資料量count是消耗資源的操作,甚至會拖慢整個庫,查詢效能問題無法解決的,應從產品設計上進行重構。例如當頻繁 需要count的查詢,考慮使用匯總表
3.遇到distinct的情況,group by方式可能效率更高。
17. delete,update語句改成select再explain
select最多導致資料庫慢,寫操作才是鎖表的罪魁禍首
18. 減少與資料庫互動的次數,儘量採用批量SQL語句
1.INSERT ... ON DUPLICATE KEY UPDATE ...,插入行後會導致在一個UNIQUE索引或PRIMARY KEY中出現重複值,則執 行舊行UPDATE,如果不重複則直接插入,影響1行。
2.REPLACE INTO類似,但它是衝突時刪除舊行。INSERT IGNORE相反,保留舊行,丟棄要插入的新行。
3.INSERT INTO VALUES(),(),(),合併插入。
19. 杜絕危險SQL
1.去掉where 1=1 這樣無意義或恆真的條件,如果遇到update/delete或遭到sql注入就恐怖了
2.SQL中不允許出現DDL語句。一般也不給予create/alter這類許可權,但阿里雲RDS只區分讀寫使用者