mysql數據庫優化以及規範

                    

一.基礎規範

1. 所有的數據庫對象名稱必須使用小寫字母並用下劃線分割(MySQL大小寫敏感,名稱要見名知意,最好不超過32字符)

2. 所有的數據庫對象名稱禁止使用MySQL保留關鍵字(如 desc、range、match、delayed 等,請參考 MySQL官方保留字 )

3.臨時庫表必須以tmp爲前綴並以日期爲後綴(tmp_)

4. 備份庫和庫必須以bak爲前綴並以日期爲後綴(bak_) 

5.所有存儲相同數據的列名和列類型必須一致。(在多個表中的字段如user_id,它們類型必須一致)

6. 禁止在數據中存儲圖片,文件二進制數據(使用文件服務器)

7. 禁止跨庫查詢(爲數據遷移和分庫分表留出餘地,降低耦合度,降低風險)

8. 禁止select * 查詢(消耗更多的cpu和io及網絡帶寬資源,無法使用覆蓋索引),SELECT語句務必指明字段名稱。

9. 禁止使用不含字段列表的insert語句(不允許insert into t values(‘a’,‘b’,‘c’))

10. 儘量把所有的字段定義爲NOT NULL並設默認值

(1)NULL的列使用索引,索引統計,值都更加複雜,MySQL更難優化

(2)NULL需要更多的存儲空間

(3)NULL只能採用IS NULL或者IS NOT NULL,而在=/!=/in/not in時有大坑

11. mysql5.5之前默認的存儲的引擎是myisam,沒有特殊要求,所有的表必須使用innodb(innodb好處支持失誤,行級鎖,高並  發下性能更好,對多核,大內存,ssd等硬件支持更好)

12. 數據庫和表的字符集儘量統一使用utf8(字符集必須統一,避免由於字符集轉換產生的亂碼,漢字utf8下佔3個字節)

13. 所有表和字段都要添加註釋COMMENT,從一開始就進行數據字典的維護

14. 儘量控制單表數據量的大小在500w以內,超過500w可以使用歷史數據歸檔,分庫分表來實現(500萬行並不是MySQL數據庫的限制。過大對於修改表結構,備份,恢復都會有很大問題)

15. 儘量做到冷熱數據分離,減小表的寬度,即建議將大字段,訪問頻度低的字段拆分到單獨的表中存儲,分離冷熱數據

(mysql限制最多存儲4096列,行數沒有限制,但是每一行的字節總數不能超過65535。列限制好處:減少磁盤io,保證熱數據的內存緩存命中率,避免讀入無用的冷數據)

16. in 操作能避免則避免,若實在避免不了,需要仔細評估 in 後邊的集合元素數量,控制在 1000 個之內

17. 根據業務區分使用數據類型,優先選擇存儲最小的數據類型。

(1)是否有效用bit即可。

(2)根據業務區分使用tinyint/int/bigint,分別會佔用1/4/8字節,

(3)根據業務區分使用char/varchar

對於字段長度固定,或者長度近似的業務場景,適合使用char,能夠減少碎片,查詢性能高,對於字段長度相差較大,或者更新較少的業務場景,適合使用varchar,能夠減少空間

(4)根據業務區分使用datetime/timestamp

前者佔用8個字節,後者佔用4個字節,存儲年使用YEAR,存儲日期使用DATE,存儲時間使用datetime

timestamp範圍:‘1970-01-01 00:00:01.000000’到 ‘2038-01-19 03:14:07.999999’;

datetime範圍:’1000-01-01 00:00:00.000000’ 到 ‘9999-12-31 23:59:59.999999’。

(5)同財務相關的金額數據,採用decimal類型(不丟失精度,禁止使用 float 和 double)

18.不要使用count(列名)或count(常量)來替代count(*),count(*)是SQL92定義的標準統計行數的語法。

說明:count(*)會統計值爲NULL的行,而count(列名)不會統計此列爲NULL值的行。

19. 儘量避免使用外鍵

20. 避免使用Text或是Blob類型

21. 儘量不要使用物理刪除

(即直接刪除,如果要刪除的話提前做好備份),而是使用邏輯刪除,使用字段enable做邏輯刪除,0表示刪除或者失效,1表示有效

22. 使用 ISNULL()來判斷是否爲 NULL 值。

23 當只需要一條數據的時候,使用limit 1

24 區分in和exists, not in和not exists 原則是小表驅動大表

select * from 表A where id in (select id from 表B)

上面sql語句相當於

select * from 表A where exists(select * from 表B where 表B.id=表A.id)

區分in和exists主要是造成了驅動順序的改變,如果是exists,那麼以外層表爲驅動表,先被訪問,如果是IN,那麼先執行子查詢。所以IN適合於外表大而內表小的情況;EXISTS適合於外表小而內表大的情況。

關於not in和not exists,推薦使用not exists,不僅僅是效率問題,not in可能存在邏輯問題。如何高效的寫出一個替代not exists的sql語句?

原sql語句

select colname … from A表 where a.id not in (select b.id from B表)

高效的sql語句

select colname … from A表 Left join B表 on where a.id = b.id where b.id is null

取出的結果集:A表不在B表中的數據

25. 每個innodb表必須有一個主鍵,選擇自增id(不能使用更新頻繁的列作爲主鍵,不適用UUID,MD5,HASH,字符串列作爲主鍵)

26. 在代碼中寫分頁查詢邏輯時,若 count 爲 0 應直接返回,避免執行後面的分頁語句

二、從索引出發的規範

27. 避免建立冗餘索引和重複索引(冗餘:index(a,b,c) index(a,b) index(a))

28. 禁止給表中的每一列都建立單獨的索引

29. 區分度最高的列放在聯合索引的最左側

30. 避免使用雙%號和like,搜索嚴禁左模糊或者全模糊(如果需要請用搜索引擎來解決。索引文件具有 B-Tree 的最左前綴匹配特性,如果左邊的值未確定,那麼無法使用此索)

31. 禁止使用order by rand()進行隨機排序

32. 禁止where從句中對列進行函數轉換和計算,以及避免隱式類型轉換(例如:where age+2>18 會使age列上的索引失效。

33. 儘量使用 union all 代替 union

34. 儘量避免使用子查詢,可以把子查詢優化爲join操作(子查詢的結果集無法使用索引,子查詢會產生臨時表操作,如果子查詢數據量大會影響效率,消耗過多的CPU及IO資源)

35.【建議】 超過三個表禁止 join。(需要 join 的字段,數據類型必須絕對一致;多表關聯查詢時,保證被關聯的字段需要有索引。即使雙表 join 也要注意表索引、SQL 性能。)

36. 在varchar字段上建立索引時,必須指定索引長度,沒必要對全字段建立索引,根據實際文本區分度決定索引長度即可。

37. SQL 性能優化的目標:至少要達到 range 級別,要求是 ref 級別,如果可以是 consts最好

38. 限制每張表上的索引數量,建議單表索引不超過5個(索引會增加查詢效率,但是會降低插入和更新的速度)

39. 如果有 order by 的場景,請注意利用索引的有序性。order by 最後的字段是組合,索引的一部分,並且放在索引組合順序的最後,避免出現 file_sort 的情況,影響查詢性能。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章