前言 | 筆記歸檔
這周公司開發工作比較悠閑,工作幾乎壓在設計上游,于是整理了下公司開發的文檔,包括項目架構、服務器運維、規范、api
對接、基本依賴信息等。如下是包含其中的MySQL
開發規范,根據社區很多的博文參考以及結合自身小團隊開發情況總結。
命名規范
對象名稱必須使用小寫,多單詞統一使用下劃線分割
命名的單詞必須做到顧名思義、簡潔,表名長度不要超過16個字符,字段名稱長度不要超過32個字符
禁止使用保留字并且盡量少用含有關鍵詞來命名
臨時表必須以
tmp_
開頭、以日期結尾,備份表必須以bak_
開頭、以日期結尾
基礎規范
-
盡可能地使用
InnoDB
作為表的存儲引擎在
MySQL 5.6
以后,InnoDB
被設置成默認的存儲引擎,支持事務和行級鎖。 -
數據庫和數據表統一使用
UTF8MB4
字符編碼UTF8MB4
字符編碼支持中文儲存以及表情存儲,兼容性杠杠的。 -
所有的表和字段必須添加注釋
這個是好習慣的問題,即使做到了顧名思義,以防萬一哪天健忘或理解錯誤,同時給后人留下后路,提高維護性。使用
comment
設定注釋。 -
盡量控制表行數在500萬以內
數據量越多,則查詢的效率越低,同時會導致長時間占用高內存以及磁盤
IO
過高。數據量膨大建議采用分表、合理分區等方案。 -
盡可能采用冷熱數據分離策略
在
MySQL
中,數據表列數最大限制為4096
列 ,每條元祖數據總和大小不能超過65535
字節,常用的字段與基本不常用的字段、細分不同業務的數據分開表設計存儲,減小表寬度,保證熱數據的內存緩存命中率,降低CPU
使用率以及降低IO
流。 -
禁止以圖片、文件等二進制數據
MySQL
雖然支持對文件對象的存儲,但是開發人員是不允許、不推薦這樣做的。文件通常是很大的,轉成二進制數據將是一串很長的字符串,無疑占用數據庫很大的存儲空間,在數據庫讀寫更是消耗內存和占用大量的IO
流,最終導致查詢的效率低下。一般文件是存放于文件服務器,將文件服務器的路徑存儲于數據庫中。
行為與流程規范
禁止在線上做數據庫的壓力測試
對應的環境使用對應的數據庫比如測試環境一定要使用測試環境的數據庫
super
權限只能屬于DBA
,不能賦予項目程序-
養成查看
SQL
運行性能的習慣,可以借用性能分析工具譬如:
EXPLAIN
語句 |showprofile
|mySQLsla
等。 -
禁止在業務高峰期批量更新、查詢數據
可以在流量比較低的凌晨跑批操作。
-
活動推廣、系統上線以及平臺上新務必對流量進行評估
防患于未然、否則可能造成數據庫服務器流量瓶頸進而導致影響業務。
-
所有建表前都要確定字段的類型、長度以及索引方可建表
確保表結構設計為最優是前期數據庫最大的優化
所有對表的結構、數據的修改務必經過
DBA
的審閱和同意
表設計規范
-
盡可能每張表的索引數量控制在5個以內
索引具有提高查詢的效率的好處也有降低寫操作效率的壞處,甚至會降低查詢到的效率。同時索引也是占用內存空間的,因而應該合理控制索引的數量。
-
每一張
InnoDB
表都必須含有一個主鍵InnoDB 是一種索引組織表:數據的存儲的邏輯順序和索引的順序是相同的。每個表都可以有多個索引,但是表的存儲順序只能有一種 InnoDB是按照主鍵索引的順序來組織表的。不要使用可能會更新的列作為主鍵,同時盡量不要使用
UUID
、MD5
、HASH
等無序的字符串作為主鍵。在沒有特別的情況下,要使用自增的整型或發號器作為主鍵。 -
盡可能避免使用外鍵約束
外鍵可以保證數據的準確性、參照完整性,每次進行寫操作時都會走校驗數據知否正確的流程,將會有損寫操作的性能,數據的參照完整性建議在業務層實現。倘若字表的寫操作很少的情況下務必使用外鍵約束。
-
設置數據表架構應考慮后期擴展型
體驗產品和架構師的交流和能力、對業務的熟悉度。
-
遵循范式與冗余平衡原則
第一范式:具有原子性
第二范式:主鍵列與非主鍵列遵循完全函數依賴關系
第三范式:非主鍵列之間沒有傳遞函數依賴關系
合理的原則能夠體驗出數據庫的可操作性、穩定性以及性能
nice
。范式設計是數據結構的一種思想,但是我們應當靈活使用,一味追求三范式無疑會影響程序的性能,適當的冗余是可以提高查詢的效率的,前提要保證是主鍵的冗余。 -
控制每張表的字段在20以內,否則業務分表
數據表的寬度與內存占用的大小成正比,在進行讀寫操作時,數據庫程序將表結構與數據載入內存,當表寬度越長消耗的內存越多、越占
IO
流,導致操作的效率下降。將可能將字段按照業務細分、冷熱的條件進行分表設計。
字段設計規范
-
盡可能不要在表中建立顧名思義的擴展字段
比如
ext
、ext_1
、extend_n
,時間一長,好幾個這樣的字段,即使每一個都有comment
,也會造成SQL
的可讀性,特別是在構建SQL
語句的時候。 -
優先設置占存儲空間最小的類型和長度
合理設置字段的類型和長度,可以節省
MySQL
的表空間,是性能優化的姿勢之一。同時,索引列定義空間越大也會導致建立索引的所需空間也越大。應當嚴禁定義字段,譬如IP
應使用UNSUGNED
或者INT
結構類型,在PHP中可以使用long2ip
與ip2long
函數進行互轉性別應使用
CHAR(1)
,即定長的字符串類型... ...
-
盡可能避免使用
TEXT
、BLOB
、ENUM
數據類型MySQL 內存臨時表不支持
TEXT
、BLOB
這樣的大數據類型,如果查詢中包含這樣的數據,在排序等操作時,就不能使用內存臨時表,必須使用磁盤臨時表進行,毋庸置疑會降低查詢的效率。MySQL
對索引字段長度是有限制的,TEXT
或BLOB
類型只能使用前綴索引。 -
避免
ENUM
數據類型在
MySQL
中,存儲枚舉類型的數據在庫中,字段列中保存的值實際為整數,特別容易導致開發者混亂,同時在查詢使用排序是基于數值整型的,雖然可以使用ORDER BY FIELD()
,但是會導致索引失效,盡量避免這么做。 -
盡可能將所有的數據列定義為
NOT NULL
類型NULL
列比較特殊,需要額外的空間來保存,同時會造成索引失效。 -
使用
TIMESTAMP
與INT
替換DATETIME
存儲時間很明顯,
TIMESTAMP
與INT
占4位字節,而DATETIME
占8位字節。那么存儲時間應該如何選擇TIMESTAMP
與INT
呢?TIMESTAMP
的可讀性高而INT
的靈活性高,因而經常需要使用計算操作的應當使用INT
存儲,否則使用TIMESTAMP
。 -
金額相關的數據必須使用
DECIMAL
數據類型談到錢這個東西呢,精確是非常重要的,即便要浪費存儲空間、笑?~
DECIMAL
類型為精準浮點數,在計算時不會丟失精度,可以自定義其長度,可用于存儲比 bigint 更大的整型數據。 -
表與表關聯的鍵名保持一致或以關聯表名的縮寫為前綴
規范事項,保持規范、養成習慣,提高程序的可讀性。
-
固定長度的字符串字段務必使用
CHAR
節省存空間、降低內存使用率、提高讀寫性能。
-
使用
UNSIGNEG
存儲非負整數節省存空間、降低內存使用率、提高讀寫性能。
-
禁止敏感數據以明文形式存儲
確保信息的安全性,比如密碼、隱秘數據等。
索引規范
重要的
SQL
語句必須帶上索引作為條件-
避免冗余和重復索引
重復索引: 在相同的列上按照相同的順序創建的相同類型的索引。
冗余索引: 兩個索引按照相同的順序覆蓋了相同的列。
在一張用戶表里面,將用戶
id
設置成主鍵的同時再設置成唯一索引,那就是重復索引,如果創建了索引(a
,b
),再設置a
索引,則a為冗余索引,這兩種錯誤的操作都會降低讀寫的性能。 -
務必不要在作為查詢條件很少、或者沒有關聯的字段下建立索引
索引本身占用存儲空間,過多設置會導致查詢效率降低。比如在成績表中將分數設置為索引,這是一種錯誤的做法。
-
禁止在索引列進行數學運算和函數運算
MySQL
不擅長于運算,需要計算的應該移至代碼業務層。總而言之,凡是計算都要移至代碼業務層(MySQL
不擅長于運算)。 -
符合索引將區分度高的置前
將區分度高的索引置前可以縮短查詢的范圍,以至提高查詢的效率,特別是在
JOIN
連表查詢,提高效率特別明顯。
SQL使用規范
-
危險的
SQL
語句必須帶上索引作為條件,謹記謹記哪些是危險的
SQL
語句呢,刪、改皆為危險的語句,一定要記住帶上WHERE
。 -
建議使用預編譯語句操作數據庫
先簡單了解下
SQL
執行的流程,SQL
先解析、預編譯處理再生成執行計劃,最后調用引擎的api
方法返回執行的結果,使用預編譯的操作姿勢,在讀寫的時候可以省去預編譯的時間,終而提高執行效率。 -
嚴禁使用
SELECT *
查詢字段要什么
SELECT
什么,不能多,否則可能導致覆蓋索引失效,消耗更多的CPU
和IO
以網絡帶寬資源。 查詢語句務必帶上索引以提高查詢效率
-
必須避免數據類型隱式轉換
在
MySQL
中,數據會存在隱式轉換,當該字段發生轉換時,索引會造成失效。 -
充分利用利用索引優勢
既然設置了索引就好好充分利用好索引,將查詢的效率提至最高。
-
禁止使用相同的賬號跨庫操作
各執其職,互不越權。
-
禁止使用帶有數據值卻不帶有字段鍵名的
INSERT
操作這是一種錯誤的做法,對于表的改動后會造成比較大的影響。
INSERT INTO user VALUES ('alicfeng',23); # 應該這樣操作 INSERT INTO user (`username`,`age`) VALUES ('alicfeng',23);
-
盡可能使用
JOIN
替代子查詢操作子查詢的結果集無法使用索引,通常子查詢的結果集會被存儲到臨時表中,不論是內存臨時表還是磁盤臨時表都不會存在索引,所以查詢性能會受到一定的影響。 特別是對于返回結果集比較大的子查詢,其對查詢性能的影響也就越大。 由于子查詢會產生大量的臨時表也沒有索引,所以會消耗過多的
CPU
和IO
資源,產生大量的慢查詢。 -
盡可能避免使用
JOIN
關聯過多的表一般情況下,建議
JOIN
的表不要超過5個,JOIN
多表查詢比較耗時時間,關聯的表越多越耗時間,防止執行超時或死鎖。 -
合并操作、減少數據庫的交互
可以靈活地合并
SQL
操作,降低IO
消耗的同時也提高了執行效率,譬如UPDATE user SET username='alicfeng' FROM id=1995; UPDATE user SET age=23 FROM id=1995; # 合并操作成一條SQL UPDATE user SET username='alicfeng',age=23 FROM id=1995;
盡可能使用
IN
代替OR
語句-
禁止使用
ORDER BY RAND()
隨機排序語句會把表中所有符合條件的數據裝載到內存中,然后在內存中對所有數據根據隨機生成的值進行排序,并且可能會對每一行都生成一個隨機值,如果滿足條件的數據集非常大,就會消耗大量的
CPU
和IO
及內存資源。 -
禁止在
WHERE
語句中進行計算對列進行函數轉換或計算時會導致無法使用索引。
# 索引會失效 WHERE DATE(create_date)='20190308'; # 靈活使用[推薦] WHERE create_date>='20190308' AND create_date<'20190309';
-
使用
UNION ALL
而不是使用UNION
在已知數據沒有重復或無須刪除重復行的前提下,因為
UNION
需要重復值掃描,降低效率。 -
大批量寫操作盡可能合理地分批次處理
大批量的操作應當合理平均分批次處理,防止死鎖影響業務,同時盡量將跑批這種大操作至于凌晨操作。
-
不在數據庫做運算,務必將運算置于業務層
MySQL
不擅長數學運算和邏輯判斷。 -
禁止使用索引做運算
索引會失效。
SQL
語句簡單化-
使用事務盡量簡單化,同時控制事務執行的時間
時間長會導致長時間鎖表,造成死鎖,進而影響業務。
IN
語句參數的個數盡量控制在1000以內-
注意
LIMIT
分頁查詢效率,LIMIT
越大效率越低在使用
LIMIT
做分頁時,更改巧妙地處理查詢,譬如使用S1
替換成S2
,將有效地提高查詢的效率。# S1 SELECT `username` FROM `user` LIMIT 10000,20; # S2 SELECT `username` FROM `user` WHERE id>10000 LIMIT 20;
-
編寫
SQL
語句必須全部為大寫,每個詞必只允許只有一個空格符編寫規范,必須統一并遵循。
盡可能使用
EXIST|NOT EXIST
替代IN | NOT IN
-
禁止使用
LIKE
添加%
前綴進行模糊查詢%
前置會導致索引失效 禁止一條語句同時對多個表進行寫操作