[Mysql教程系列]介紹一下MySQL語句設計規範以及其他規範

點擊上方“Coder編程”,選擇“置頂公衆號”

技術文章第一時間送達!

mysql.jpg

語句設計規範

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~

微信公衆號
     我知道你 “在看
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章