MySQL數據庫操做規範

MySQL數據庫操做規範

文檔說明:
該文檔旨在對MySQL數據庫的使用作一個統一的約定和規範;以便使你們更明確、更有效的用好數據庫,最終使數據庫發揮更好的做用,從而提高產品的質量。html

1、基礎規範

1.一、【強制】使用InnoDB存儲引擎。
解讀:InnoDB存儲引擎是MySQL默認存儲引擎,支持事務和行級鎖,併發性能更好,CPU及內存緩存頁優化使得資源利用率更高,而且MyISAM在8.0中考慮移除了。前端

1.二、【強制】使用統一的字符集(utf8或utf8mb4),若是有存儲emoji表情之類的,則須要使用utf8mb4,不然使用utf8便可。
解讀:無需轉碼,無亂碼風險;utf8mb4向下兼容utf8但存儲使用的空間會比utf8略大。mysql

1.三、【強制】表、字段必須加入中文註釋,註釋要言簡意賅。
解讀:便於識別表和字段的用途,有利於維護;
反例:t_company_organization_scope_employee 能夠採用縮寫改爲t_com_org_scope_empsql

1.四、【強制】禁止使用存儲過程、視圖、觸發器、Event。
解讀:高併發大數據的互聯網業務,架構設計思路是「解放數據庫CPU,將計算轉移到服務層」,併發量大的狀況下,這些功能極可能將數據庫拖死,業務邏輯放到服務層具有更好的擴展性,可以輕易實現「增機器就加性能」。數據庫擅長存儲與索引,CPU計算仍是上移到業務層。放到業務層也便於管理和維護。數據庫

1.五、【強制】禁止存儲大文件或者圖片。
解讀:大文件和圖片存儲在文件系統,數據庫裏存URL信息。後端

2、數據庫設計規範

一、命名規範

1.1【強制】庫名、表名、字段名:必須使用小寫字母,下劃線風格,名稱要簡潔明瞭,長度不超過32個字符。
禁止數字開頭,禁止兩個下劃線中間只出現數字,禁止複數名詞和駝峯命名,禁止出現大寫或中文,禁止使用中劃線。
解讀:
正例:getter_admin,task_config,level3_name
反例:GetterAdmin,taskConfig,level_3_name
備註:對於中劃線,當前公司項目的庫名已經使用了,處於更改爲本考慮能夠統一使用中劃線,但表名、字段名仍然禁止使用中劃線。緩存

1.2【建議】對同一業務模塊或關聯功能的表應當使用相同前綴來區分。
解讀:統一的命名規則便於表格的使用和維護。
正例:如acl_xxx,house_xxx,user_xxx;其中前綴一般爲這個表的模塊或依賴主實體對象的名字,一般來說表名爲:業務動做類型,或是業務類型;網絡

1.3【強制】命名中不容許出現MYSQL數據庫中的保留字。如desc、range、match、delayed、date、now等,請參考MySQL官方保留字:
https://dev.mysql.com/doc/refman/5.7/en/keywords.html架構

1.4【建議】索引命名格式爲:索引類型_字段名縮寫。普通索引名idx_xxx,惟一索引名un_xxx。
解讀:
統一風格便於使用和維護。併發

二、表設計規範

2.1【強制】單表中列的數量必須小於30,單庫表的數量要控制在500個之內。
解讀:
一般來講列數越多,物理文件越大,表的效率越差。
庫中表越多,物理文件就越多,空間消耗就越大。

2.2【強制】表中必須明確指定主鍵,無特殊狀況則要使用自增的UNSIGNED BIGINT型主鍵。
解讀:主鍵的遞增可使數據行在物理文件中按順存放,能夠避免page分裂,減小表碎片的產生提高空間和內存的使用,繼而提升寫入、查詢的性能。

2.3【強制】禁止使用外鍵,若是有外鍵完整性約束,須要應用程序控制。
解讀:外鍵會致使表與表之間耦合,UPDATE與DELETE操做都會涉及相關聯的表,十分影響sql的性能,甚至會形成死鎖。

三、字段設計規範

3.1【強制】表的各個字段必需要設置NOT NULL約束,特別是做爲過濾條件的列!
解讀:
1)全部NULL值在索引中對於一個KEY,在MySQL5.6.17及以後,IS NULL等同於等值查詢,能夠用索引;
2)NULL字段在物理文件上是經過打標籤的方式記錄的,對於這種類型MySQL內部須要進行特殊處理,增長數據庫處理記錄的複雜性;同等條件下,表中有較多個NULL值字段的時候,數據庫的處理性能會下降不少;
3)NULL字段的查詢語句優化空間不大,對NULL的處理只能採用IS NULL或IS NOT NULL,並且沒法使用索引;

3.2【建議】根據實際須要來爲字段設置默認值。
解讀:
默認值能夠經過自動補充列值的方式,在列值不全的狀況下可成功向表中寫入數據;防止了人爲疏忽而致使程序失敗的可能。但這也偏偏是埋下了雷,使得在程序異常時很難發現問題。
爲了程序更加健壯,推薦在設置了NOT NULL的前提下不提供默認值,直接報錯後進行處理。

若是須要設置默認值約束請使用如下默認值:
TINYINT/SMALLINT/INT/BIGINT 整數類型默認值:0
CHAR/VARCHAR 字符類型默認值:'' (空字符串)
DATE 類型默認值:'0000-00-00'
TIME 類型默認值:'00:00:00'
DATETIME 類型默認值:'0000-00-00 00:00:00'

注意:
有一種誤區:只要指定了默認值就OK了,NOT NULL就是多餘的;在插入時對相應列賦值爲NULL時插入表裏會自動填充默認值的。
這個認識是錯誤的,若是沒有NOT NULL,即便有默認值在插入NULL時也不會填充默認值(自增主鍵除外)。
例如:

CREATE TABLE t1(
id      UNSIGNED BIGINT NOT NULL AUTO_INCREMENT ,
name VARCHAR(10) DEFAULT 'xxx' COMMENT '姓名',
age    UNSIGNED SMALLINT DEFAULT 0 COMMENT '年齡',
PRIMARY KEY(id)
)ENGINE=INNODB COMMENT='用戶信息' ;
mysql> INSERT INTO aa (id,NAME,age) VALUES(NULL,NULL,1);

結果:

mysql> select * from t1;
+----+------+------+
| id | name | age  |
+----+------+------+
|  1 | NULL |    1 |
+----+------+------+
1 rows in set (0.00 sec)

看到了吧,name雖然有默認值'xxx'可是在指定NULL後,並無用默認值填充!!

3.3【強制】使用UNSIGNED存儲非負整數。
解讀:
能夠擴大數值的使用範圍,減小範圍查找時MySQL無心義的負值查找、比對的資源浪費。

3.4【強制】小數類型用DECIMAL或者對數值擴大後使用int/bigint 類型來存儲,禁止使用FLOAT和DOUBLE。
解讀:
FLOAT和DOUBLE在存儲、計算的時候,存在精度損失的問題,極可能在值的比較時,獲得不正確結果。若是存儲的數據範圍超過DECIMAL的範圍,建議將數據拆成整數和小數分開存儲。
對於數值精度要求高的場景,特別是在存儲貨幣的場景中一般是經過將‘元’換成‘分’後進行整數存儲,在讀取或寫入的時候,進行轉換。

3.5【強制】枚舉類型禁止使用ENUM,可以使用TINYINT代替。
解讀:
a)增長新的ENUM值要作DDL操做;
b)ENUM的內部實際存儲就是整數;

3.6【強制】若是存儲的字符串長度幾乎相等,請使用定長字符串CHAR類型。
解讀:
在物理文件中定長的字符串是使用統一大小的空間存放的,這在查詢時MySQL可使用統一的偏移量來獲取數據,提高的性能。

3.7【建議】VARCHAR是可變長字符串,必定要根據實際狀況按需設置長度;長度最好不要超過250個漢字字符(utf8編碼)。
解讀:
當VARCHAR存放的字符過多時,在物理文件中存放時會產生行溢出現象;這會影響性能。
選擇合適的字符存儲長度,不但節約數據庫表空間、節約索引存儲,更重要的是提高檢索速度。

3.8【建議】使用VARCHAR存儲電話號碼。
解讀:
a)涉及到區號或者國家代號,可能出現+-();
b)電話號碼不會作數學運算;
c)VARCHAR能夠支持模糊查詢,例如:LIKE '138%';

3.9【建議】網絡IP字段,除特殊狀況外一概用INT UNSIGNED來記錄(IP可經過INET_ATON函數轉換爲數值)。
解讀:
將IP地址轉換爲數值來存取,有利於性能提高。

3.10【強制】禁止使用TEXT、BLOB類型,如要使用能夠其將內容垂直拆分到子表中。
解讀:
TEXT、BLOB這些大類型在物理存儲時會使用行溢出的方式來存儲,這會浪費更多的磁盤和內存空間。在從物理文件中讀取這類對象時會額外消耗資源,並且大量的大字段在查詢時會將內存中的大量熱數據淘汰掉,致使內存命中率急劇下降,影響數據庫性能。
若是必定要使用這類對象,能夠將這些字段拆分出去,單獨存放;這樣保證了主表的瘦小。

3.11【建議】字段容許適當冗餘,以提升性能,可是必須考慮冗餘數據的同步狀況。
解讀:
字段的冗餘能夠減小表之間的關聯,使用得當能夠提高性能。
冗餘字段應遵循:不是頻繁修改的字段,不是VARCHAR超長字段,更不能是TEXT字段。

3.12【強制】禁止在數據庫中存儲明文密碼,把密碼加密後存儲。

四、索引設計規範

說明:區分度是指列中存放的數據值中惟一值個數佔中總值個數的比例。

4.1【建議】禁止在更新十分頻繁、區分度不高的屬性上創建索引。
解讀:
a)更新會變動B+樹,更新頻繁的字段創建索引會大大下降數據庫性能;
b)"性別"這種區分度不大的屬性,創建索引是沒有什麼意義的,不能有效過濾數據,性能與全表掃描相似;除非數據存在嚴重傾斜,而且恰好只查詢那部分小範圍數據時才考慮創建。

4.2【建議】業務上具備惟一特性的字段(即便是組合字段的惟一),必須創建惟一索引。
解讀:不要覺得惟一索引影響了INSERT速度,這個速度損耗能夠忽略,但提升查找速度是明顯的;另外,即便在應用層作了很是完善的校驗和控制,也要作惟一索引。

4.3【建議】在VARCHAR字段上創建索引時,必須指定索引長度,不必對全字段創建索引,根據實際文本區分度決定索引長度。
解讀:索引的長度與區分度是一對矛盾體,通常對字符串類型數據,長度爲20的索引,區分度會高達90%以上,可使用COUNT(DISTINCT LEFT(列名, 索引長度))/COUNT(主鍵)的區分度來肯定。

4.4【建議】索引數量應不超過列總數的40%(通常單表索引建議控制在5個之內)。
解讀:索引過多會增長存儲開銷和增刪改的開銷。

4.5【建議】儘可能使用組合索引,創建組合索引時必須把區分度高的、使用頻率高的字段放在前面,索引中字段數不容許超過3個。
解讀:可以更加有效的過濾數據,索引上字段超過3個時,實際的過濾數據效果已經很差了,並且還佔用了空間。

4.6【強制】在排序、分組、取惟一的字段上建立索引,常常與其餘表進行關聯的表,在關聯字段上應該創建索引,常常出如今WHERE子句中的字段,特別是大表的字段,應該創建索引。

3、SQL使用規範

一、SQL書寫規則

1.1【建議】SQL語句的大小寫風格要統一。
SQL語句中出現的全部表名、表別名、字段名等自定義數據庫對象都應小寫。
SQL語句中出現的系統保留字、內置函數名、SQL保留字等都應大寫,不建議使用保留字。
解讀:
大小寫區分開,便於對象的識別;
如:
SELECT c1,c2 FROM tab WHERE c1='xxx';
INSERT INTO tab(c1,c2,c3) VALUES ('a','b',30);

1.2【強制】禁止使用MySQL特有的非標準SQL語法,全部SQL都必須使用標準寫法。
解讀:
MySQL支持多種非標準SQL語法,這會使得SQL書寫變得混亂,難以維護;因此必定要按標準SQL來書寫。

MySQL支持的非標準INSERT語法:
1)INSERT INTO employees SET employee_name='John',date='2018-06-15',mployee_age=30;
2)INSERT INTO employees(employee_name,date,mployee_age)
VALUES ('John','2018-06-15',30)
ON DUPLICATE KEY UPDATE ;

標準寫法:
INSERT INTO employees(employee_name,date,mployee_age)
VALUES ('John','2018-06-15',30);

1.3【建議】SQL語句中表的別名應簡短明瞭,宜反映表名的實際意義。
解讀:表名比較長的時候必定要使用別名來優化SQL書寫方式;這樣的好處有:
1)方便表對象的引用;
2)更有利於SQL的閱讀、管理;
3)減少慢SQL被截斷的可能(慢SQL以表方式存放的狀況);
4)最重要的還能夠節省數據庫內存。

1.4【建議】同一項目的SQL書寫格式應該統一。

二、可讀性規則

2.1【強制】不容許使用SELECT ,必須指定列名;須要什麼就索取什麼。
解讀:
a)對
的解析以及讀取那些不須要的列會增長CPU、IO、NET消耗;
b)不能有效的利用覆蓋索引;
c)使用SELECT *容易在增長或者刪除字段後出現程序BUG;

2.2【強制】INSERT必須明確指定插入的字段名。
解讀:
避免在增長或者刪除字段後出現程序BUG。
正例:INSERT INTO tab(c1,c2,c3) VALUES ('a','b',30);

2.3【強制】不等於統一使用"<>"。
SQL認爲"<>"和"!="是等價的,都表明不等於的意義。爲了統一,不等於一概使用"!="表示。

2.4【強制】在錶鏈接時要對錶設置別名,別名要簡潔明瞭,控制在5個英文字符內,不易過長。

2.5【強制】應避免寫複雜的SQL語句。
解讀:
a) 增長SQL可讀性;
b) 複雜SQL每每效率不是很好。

2.6【強制】建議不用now(),uuid()等函數來填充SQL。
解讀:
在MySQL使用函數來計算結果值,會消耗MySQL的CPU資源。
如:INSERT INTO tab(a,b,c) VALUES('aa','bb',NOW()); 建議:c的值直接從前端傳入。

三、性能相關規則

3.1【強制】避免在數據庫中進⾏數學運算(MySQL不擅長數學運算和邏輯判斷)

3.2【強制】SQL語句應避免對大表的全表掃描操做,對大表的操做應儘可能使用索引。

3.3【強制】SQL語句應避免’硬’刪除的操做,應該採用修改狀態的’軟’刪除。
解讀:
頻繁的物理刪除會使表的碎片增多,影響性能。

3.4【強制】應按照業務須要使用事務,同時應保持事務簡短,避免大事務,確保整個事務涉及的數據庫對象不要超過5個,執行時間不要超過3秒。

3.5【強制】每一個SQL返回結果的行數不能太多,用多少取多少,要控制在500行之內。統計分析除外。

3.6【強制】在事務完整性的基礎上,SQL語句應在程序中顯式使用 COMMIT,ROLLBACK,儘快提交事務,釋放系統資源。

3.7【強制】對大量數據的更新要打散後批量更新,不要一次更新太多數據。(大事務)

3.8【強制】對大量數據插入時不要使用逐條的INSERT語句進行插入,要使用合併插入的方式。
解讀:由於MySQL默認開啓了自動提交,若是一條條執行就意味着每條結束後都有執行一次COMMIT,這樣嚴重影響性能。合併插入則是一次COMMIT。
低效:
INSERT INTO emp (empno,ename,deptno) VALUES(1,'a',10);
INSERT INTO emp (empno,ename,deptno) VALUES(2,'b',20);
INSERT INTO emp (empno,ename,deptno) VALUES(3,'c',30);
INSERT INTO emp (empno,ename,deptno) VALUES(4,'d',10);
INSERT INTO emp (empno,ename,deptno) VALUES(5,'e',10);
INSERT INTO emp (empno,ename,deptno) VALUES(6,'f',10);

高效:
INSERT INTO emp (empno,ename,deptno)
Values (1,'a',10),(2,'b',20),(3,'c',30), (4,'d',10), (5,'e',10),(6,'f',10);

3.9【強制】禁止使用屬性的隱式轉換。
解讀:
隱式轉換會致使索引失效,
例如:
t_user的phone是VARCHAR類型,且有索引;
SELECT uid FROM t_user WHERE phone=13812345678; 會致使全表掃描,而不能命中phone索引,由於發生了數值到字符串的隱式轉換。

3.10【強制】去掉where 1=1 這樣無心義或恆真的條件,若是遇到update/delete或遭到sql注入就恐怖了。

3.11【建議】減小子查詢的使用。
解讀:子查詢除了可讀性差以外,一般會在必定程度上影響了SQL運行效率. 應儘可能減小子查詢的使用,採用關聯或其餘效率更高、可讀性更好的方式實現。

3.12【建議】禁止在WHERE條件的列上使用函數或者表達式,要將其改寫到等號右邊。
解讀:
在過濾條件的列上使用函數,會致使列上的索引沒法被使用;
錯誤:SELECT uid FROM t_user WHERE DATE(day)='2017-02-15'; ==>會致使全表掃描
正確:SELECT uid FROM t_user WHERE day>='2017-02-15 00:00:00' and day<='2017-02-15 23:59:59'

3.13【建議】禁止負向查詢,以及%或_開頭的模糊查詢。
解讀:反向操做是不會用到索引的。

a)負向查詢條件:NOT、<>、<>、!<、!>、NOT IN、NOT LIKE等,會致使全表掃描;
b)%或_開頭的模糊查詢,會致使全表掃描;

3.14【建議】SQL語句應避免沒必要要的分組和排序。
解讀:分組和排序操做會用到臨時表,影響性能。

3.15【建議】SQL語句儘量避免多表聯合的複雜查詢。

3.16【建議】禁止對大表進行關聯查詢,禁止大表使用子查詢
解讀:關聯會產生臨時表,並且大表的數據量大,會進一步消耗更多內存與CPU,極大影響數據庫性能。

3.17【建議】禁止使用OR條件,若是是同一列的不一樣值的OR語句能夠改成IN查詢。
解讀:MySQL在執行時內部會對這類OR語句改寫爲IN語句,若是咱們人爲的將最終SQL改寫成IN,那MySQL就不須要消耗資源去作轉換了。
如:
錯誤:SELECT c1,c2 FROM tab WHERE c3 =1 OR c3 = 2;
正確:SELECT c1,c2 FROM tab WHERE c3 IN (1,2);

3.18【建議】禁止使用OR條件,若是是不一樣列的OR語句能夠考慮用UNION替換OR。
解讀:
將OR運算的邏輯判斷使用分條件查詢來實現,能夠很好的提升查詢效率。

低效:
SELECT loc_id , loc_desc , region
FROM location
WHERE loc_id = 10 OR region = 'MELBOURNE';

高效:
SELECT loc_id , loc_desc , region
FROM location
WHERE loc_id = 10
UNION
SELECT loc_id , loc_desc , region
FROM location
WHERE region = 'MELBOURNE';

3.19【建議】IN裏包含的值的個數建議控制在100之內,過多IN的效率不高。

3.20【建議】在使用union時優先考慮使用union all,少使用union。
解讀:
union all不去重,少了排序操做,速度相對比union要快,若是沒有去重的需求,優先使用union all。

3.21【建議】用>=替代>,用<=代替<,幫助MySQL肯定下限和上限。
解讀:
若是不使用’=’指定上下限,MySQL須要本身去分析查找這個邊界值,浪費了資源。

四、其餘建議

4.1【強制】頁面搜索嚴禁左模糊或者全模糊,若是須要請走搜索引擎來解決。
解讀:索引具備B-Tree的最左前綴匹配特性,若是左邊的值未肯定,那麼沒法使用此索引。

4.2【強制】應用程序必須捕獲SQL異常,並有相應處理.

4.3【強制】應用程序要合理配置重連、連接過時時間,數據庫對空閒連接默認超時時間是8小時(超過這個時間的會被殺掉),但對於被頻繁鏈接的前端業務庫,一般線上每每設置在30分,而新建鏈接不頻繁後端一般會相應調長一點,大概1-3小時;這樣可使空閒的連接及早退出從而釋放數據庫內存資源。

4.4【強制】不一樣業務模塊必須使用不一樣的帳號來鏈接數據庫,便於問題排查和權限管理

相關文章
相關標籤/搜索