點擊上方“Coder編程”,選擇“置頂公衆號”
技術文章第一時間送達!
語句設計規範
1、使用預編譯語句
只傳參數,比傳遞SQL語句更高效
一次解析,多次使用
降低SQL注入概率
2、避免隱式轉換
會導致索引失效
3、充分利用前綴索引
必須是最左前綴
不可能同時用到兩個範圍條件
不使用%前導的查詢,如like “%ab”
4、不使用負向查詢,如not in/like
無法使用索引,導致全表掃描
全表掃描導致buffer pool利用率降低
5、避免使用存儲過程、觸發器、UDF、events等
讓數據庫做最擅長的事
降低業務耦合度,爲sacle out、sharding留有餘地
避開BUG
6、避免使用大表的JOIN
MySQL最擅長的是單表的主鍵/二級索引查詢
JOIN消耗較多內存,產生臨時表
7、避免在數據庫中進行數學運算
MySQL不擅長數學運算和邏輯判斷
無法使用索引
7、減少與數據庫的交互次數
INSERT … ON DUPLICATE KEY UPDATE
REPLACE INTO、INSERT IGNORE 、INSERT INTO VALUES(),(),()
UPDATE … WHERE ID IN(10,20,50,…)
8、合理的使用分頁
限制分頁展示的頁數
只能點擊上一頁、下一頁
採用延遲關聯
如何正確的使用分頁?
假如有類似下面分頁語句:SELECT * FROM table ORDER BY id LIMIT 10000, 10
由於MySQL裏對LIMIT OFFSET的處理方式是取出OFFSET+LIMIT的所有數據,然後去掉OFFSET,返回底部的LIMIT。所以,在OFFSET數值較大時,MySQL的查詢性能會非常低。可以使用id > n 的方式進行解決:
使用id > n 的方式有侷限性,對於id不連續的問題,可以通過翻頁的時候同時傳入最後一個id方式來解決。
//輸出時,找出當前結果集中的最大最小id
//下一頁
http://example.com/page.php?last=100
select * from table where id<100 order by id desc limit 10
//上一頁
http://example.com/page.php?first=110
select * from table where id>110 order by id desc limit 10
這種方式比較大的缺點是,如果在瀏覽中有插入/刪除操作,翻頁不會更新,而總頁數可能仍然是根據新的count(*) 來計算,最終可能會產生某些記錄訪問不到。爲了修補這個問題,可以繼續引入當前頁碼以及在上次翻頁以後是否有插入/刪除等影響總記錄數的操作並進行緩存
其他變種方式:
select * from table where id >= (select id from table order by id limit #offset#, 1)
9、拒絕大SQL,拆分成小SQL
充分利用QUERY CACHE
充分利用多核CPU
10、使用in代替or,in的值不超過1000個
11、禁止使用order by rand()
12、使用EXPLAIN診斷,避免生成臨時表
EXPLAIN語句(在MySQL客戶端中執行)可以獲得MySQL如何執行SELECT語句的信息。通過對SELECT語句執行EXPLAIN,可以知曉MySQL執行該SELECT語句時是否使用了索引、全表掃描、臨時表、排序等信息。儘量避免MySQL進行全表掃描、使用臨時表、排序等。詳見官方文檔。
13、用union all而不是union
union all與 union有什麼區別?
union和union all關鍵字都是將兩個結果集合併爲一個,但這兩者從使用和效率上來說都有所不同。
union在進行錶鏈接後會篩選掉重複的記錄,所以在錶鏈接後會對所產生的結果集進行排序運算,刪除重複的記錄再返回結果。如:
select * from test_union1
union
select * from test_union2
這個SQL在運行時先取出兩個表的結果,再用排序空間進行排序刪除重複的記錄,最後返回結果集,如果表數據量大的話可能會導致用磁盤進行排序。
而union all只是簡單的將兩個結果合併後就返回。這樣,如果返回的兩個結果集中有重複的數據,那麼返回的結果集就會包含重複的數據了。
從效率上說,union all要比union快很多,所以,如果可以確認合併的兩個結果集中不包含重複的數據的話,那麼就使用union all,如下:
select * from test_union1
union all
select * from test_union
14、程序應有捕獲SQL異常的處理機制
15、禁止單條SQL語句同時更新多個表
16、不使用select * ,SELECT語句只獲取需要的字段
消耗CPU和IO、消耗網絡帶寬
無法使用覆蓋索引
減少表結構變更帶來的影響
因爲大,select/join 可能生成臨時表
17、UPDATE、DELETE語句不使用LIMIT
18、INSERT語句必須顯式的指明字段名稱,不使用INSERT INTO table()
19、INSERT語句使用batch提交(INSERT INTO table VALUES(),(),()……),values的個數不超過500
20、統計表中記錄數時使用COUNT(*),而不是COUNT(primary_key)和COUNT(1) 備註:僅針對Myisam
21、數據更新建議使用二級索引先查詢出主鍵,再根據主鍵進行數據更新
22、禁止使用跨庫查詢
23、禁止使用子查詢,建議將子查詢轉換成關聯查詢
24、針對varchar類型字段的程序處理,請驗證用戶輸入,不要超出其預設的長度;
分表規範
單表一到兩年內數據量超過500w或數據容量超過10G考慮分表,需提前考慮歷史數據遷移或應用自行刪除歷史數據,採用等量均衡分表或根據業務規則分表均可。要分表的數據表必須與DBA商量分表策略
用HASH進行散表,表名後綴使用十進制數,下標從0開始
按日期時間分表需符合YYYY[MM][DD][HH]格式
採用合適的分庫分表策略。例如千庫十表、十庫百表等
禁止使用分區表,分區表對分區鍵有嚴格要,分區表在表變大後執行DDL、SHARDING、單表恢復等都變得更加困難。
拆分大字段和訪問頻率低的字段,分離冷熱數據
行爲規範
批量導入、導出數據必須提前通知DBA協助觀察
禁止在線上從庫執行後臺管理和統計類查詢
禁止有super權限的應用程序賬號存在
產品出現非數據庫導致的故障時及時通知DBA協助排查
推廣活動或上線新功能必須提前通知DBA進行流量評估
數據庫數據丟失,及時聯繫DBA進行恢復
對單表的多次alter操作必須合併爲一次操作
不在MySQL數據庫中存放業務邏輯
重大項目的數據庫方案選型和設計必須提前通知DBA參與
對特別重要的庫表,提前與DBA溝通確定維護和備份優先級
不在業務高峯期批量更新、查詢數據庫其他規範
提交線上建表改表需求,必須詳細註明所有相關SQL語句
其他規範
日誌類數據不建議存儲在MySQL上,優先考慮Hbase或OceanBase,如需要存儲請找DBA評估使用壓縮表存儲。
推薦
文末
文章收錄至
Github: https://github.com/CoderMerlin/coder-programming
Gitee: https://gitee.com/573059382/coder-programming
歡迎關注並star~