去哪⼉網MySQL開發規範整理

1.命名規範
(1)庫名、表名、字段名必須使⽤⼩寫字⺟,並採⽤下劃線分割。
(2)庫名、表名、字段名禁⽌超過32個字符。
(3)庫名、表名、字段名必須⻅名知意。命名與業務、產品線等相關聯。
(4)庫名、表名、字段名禁⽌使⽤MySQL保留字。
(5)臨時庫、表名必須以tmp爲前綴,並以⽇期爲後綴。例如 tmp_test01_20130704。
(6)備份庫、表必須以bak爲前綴,並以⽇期爲後綴。例如 bak_test01_20130704。

2.基礎規範
(1)使⽤INNODB存儲引擎。
(2)表字符集使⽤UTF8,必要時可申請使⽤UTF8MB4字符集。
(3)所有表都需要添加註釋;除主鍵外的其他字段都需要增加註釋。推薦採⽤英⽂標點,避免出現亂碼。 
【建表語句⽰例】
(4)禁⽌在數據庫中存儲圖⽚、⽂件等⼤數據。
(5)每張表數據量建議控制在5000W以內。
(6)禁⽌在線上做數據庫壓⼒測試。
(7)禁⽌從測試、開發環境直連數據庫。

3.庫表設計
(1)禁⽌使⽤分區表。
(2)將⼤字段、訪問頻率低的字段拆分到單獨的表中存儲,分離冷熱數據。
(3)推薦使⽤HASH進⾏散表,表名後綴使⽤⼗進制數,數字必須從0開始。
(4)按⽇期時間分表需符合YYYY[MM][DD][HH]格式,例如2013071601。年份必須⽤4位數字表⽰。例如按
⽇散表user_20110209、 按月散表user_201102。
(5)採⽤合適的分庫分表策略。例如千庫⼗表、⼗庫百表等。

4.字段設計
(1)建議使⽤UNSIGNED存儲⾮負數值。
(2)建議使⽤INT UNSIGNED存儲IPV4。
(3)⽤DECIMAL代替FLOAT和DOUBLE存儲精確浮點數。例如與貨幣、⾦融相關的數據。
(4)INT類型固定佔⽤4字節存儲,例如INT(4)僅代表顯⽰字符寬度爲4位,不代表存儲⻓度。
(5)區分使⽤TINYINT、SMALLINT、MEDIUMINT、INT、BIGINT數據類型。例如取值範圍爲0-80時,使⽤
TINYINT UNSIGNED。
(6)強烈建議使⽤TINYINT來代替ENUM類型。
(7)儘可能不使⽤TEXT、BLOB類型。
(8)禁⽌在數據庫中存儲明⽂密碼。
(9)使⽤VARBINARY存儲⼤⼩寫敏感的變⻓字符串或⼆進制內容。
(10)使⽤儘可能⼩的VARCHAR字段。VARCHAR(N)中的N表⽰字符數⽽⾮字節數。
(11)區分使⽤DATETIME和TIMESTAMP。存儲年使⽤YEAR類型。存儲⽇期使⽤DATE類型。 存儲時間(精確
到秒)建議使⽤TIMESTAMP類型。
(12)所有字段均定義爲NOT NULL。

5.索引規範
(1)單張表中索引數量不超過5個。
(2)單個索引中的字段數不超過5個。
(3)索引名必須全部使⽤⼩寫。
(4)⾮唯⼀索引按照“idx_字段名稱[_字段名稱]”進⾏命名。例如idx_age_name。
(5)唯⼀索引按照“uniq_字段名稱[_字段名稱]”進⾏命名。例如uniq_age_name。
(6)組合索引建議包含所有字段名,過⻓的字段名可以採⽤縮寫形式。例如idx_age_name_add。
(7)表必須有主鍵,推薦使⽤UNSIGNED⾃增列作爲主鍵。
(8)唯⼀鍵由3個以下字段組成,並且字段都是整形時,可使⽤唯⼀鍵作爲主鍵。其他情況下,建議使⽤⾃增列
或發號器作主鍵。
(9)禁⽌冗餘索引。
(10)禁⽌重複索引。
(11)禁⽌使⽤外鍵。
(12)聯表查詢時,JOIN列的數據類型必須相同,並且要建⽴索引。
(13)不在低基數列上建⽴索引,例如“性別”。
(14)選擇區分度⼤的列建⽴索引。組合索引中,區分度⼤的字段放在最前。
(15)對字符串使⽤前綴索引,前綴索引⻓度不超過8個字符。
(16)不對過⻓的VARCHAR字段建⽴索引。建議優先考慮前綴索引,或添加CRC32或MD5僞列並建⽴索引。
(17)合理創建聯合索引,(a,b,c) 相當於 (a) 、(a,b) 、(a,b,c)。
(18)合理使⽤覆蓋索引減少IO,避免排序。

6.SQL設計
(1)使⽤prepared statement,可以提升性能並避免SQL注⼊。
(2)⽤IN代替OR。SQL語句中IN包含的值不應過多,應少於1000個。
(3)禁⽌隱式轉換。數值類型禁⽌加引號;字符串類型必須加引號。
(4)避免使⽤JOIN和⼦查詢。必要時推薦⽤JOIN代替⼦查詢。
(5)避免在MySQL中進⾏數學運算和函數運算。
(6)減少與數據庫交互次數,儘量採⽤批量SQL語句。
(7)拆分複雜SQL爲多個⼩SQL,避免⼤事務。
(8)獲取⼤量數據時,建議分批次獲取數據,每次獲取數據少於2000條,結果集應⼩於1M。
(9)⽤UNION ALL代替UNION。
(10)統計⾏數⽤COUNT(*)。
(11)SELECT只獲取必要的字段,禁⽌使⽤SELECT *。
(12)SQL中避免出現now()、rand()、sysdate()、current_user()等不確定結果的函數。
(13)INSERT語句必須指定字段列表,禁⽌使⽤ INSERT INTO TABLE()。
(14)禁⽌單條SQL語句同時更新多個表。
(15)避免使⽤存儲過程、觸發器、視圖、⾃定義函數等。
(16)建議使⽤合理的分⻚⽅式以提⾼分⻚效率。
(17)禁⽌在從庫上執⾏後臺管理和統計類功能的QUERY,必要時申請統計類從庫。
(18)程序應有捕獲SQL異常的處理機制,必要時通過rollback顯式回滾。
(19)重要SQL必須被索引:update、delete的where條件列、order by、group by、distinct字段、多表join
字段。
(20)禁⽌使⽤%前導查詢,例如:like “%abc”,⽆法利⽤到索引。
(21)禁⽌使⽤負向查詢,例如 not in、!=、not like。
(22)使⽤EXPLAIN判斷SQL語句是否合理使⽤索引,儘量避免extra列出現:Using File Sort、Using 
Temporary。
(23)禁⽌使⽤order by rand()。

7.⾏爲規範
(1)表結構變更必須通知DBA進⾏審覈。
(2)禁⽌有super權限的應⽤程序賬號存在。
(3)禁⽌有DDL、DCL權限的應⽤程序賬號存在。
(4)重⼤項⺫的數據庫⽅案選型和設計必須提前通知DBA參與。
(5)批量導⼊、導出數據必須通過DBA審覈,並在執⾏過程中觀察服務。
(6)批量更新數據,如UPDATE、DELETE操作,必須DBA進⾏審覈,並在執⾏過程中觀察服務。
(7)產品出現⾮數據庫導致的故障時,如被攻擊,必須及時通DBA,便於維護服務穩定。
(8)業務部⻔程序出現BUG等影響數據庫服務的問題,必須及時通知DBA,便於維護服務穩定。
(9)業務部⻔推⼲活動或上線新功能,必須提前通知DBA進⾏服務和訪問量評估,並留出必要時間以便DBA完
成擴容。
(10)出現業務部⻔⼈爲誤操作導致數據丟失,需要恢復數據的,必須第⼀時間通知DBA,並提供準確時間點、
誤操作語句等重要線索。
(11)提交線上建表改表需求,必須詳細註明涉及到的所有SQL語句(包括INSERT、DELETE、UPDATE),便
於DBA進⾏審覈和優化。
(12)對同⼀個表的多次alter操作必須合併爲⼀次操作。
(13)不要在MySQL數據庫中存放業務邏輯。

8.FAQ
1.庫名、表名、字段名必須使⽤⼩寫字⺟,並採⽤下劃線分割。
a)MySQL有配置參數lower_case_table_names,不可動態更改,linux系統默認爲 0,即庫表名以實際情況
存儲,⼤⼩寫敏感。如果是1,以⼩寫存儲,⼤⼩寫不敏感。如果是2,以實際情況存儲,但以⼩寫⽐較。
b)如果⼤⼩寫混合使⽤,可能存在abc,Abc,ABC等多個表共存,容易導致混亂。
c)字段名顯⽰區分⼤⼩寫,但實際使⽤不區分,即不可以建⽴兩個名字⼀樣但⼤⼩寫不⼀樣的字段。
d)爲了統⼀規範, 庫名、表名、字段名使⽤⼩寫字⺟。
2.庫名、表名、字段名禁⽌超過32個字符。
庫名、表名、字段名⽀持最多64個字符,但爲了統⼀規範、易於辨識以及減少傳輸量,禁⽌超過32個字符。

3.使⽤INNODB存儲引擎。
INNODB引擎是MySQL5.5版本以後的默認引擘,⽀持事務、⾏級鎖,有更好的數據恢復能⼒、更好的併發性
能,同時對多核、⼤內存、SSD等硬件⽀持更好,⽀持數據熱備份等,因此INNODB相⽐MyISAM有明顯優
勢。
4.庫名、表名、字段名禁⽌使⽤MySQL保留字。
當庫名、表名、字段名等屬性含有保留字時,SQL語句必須⽤反引號引⽤屬性名稱,這將使得SQL語句書寫、
SHELL腳本中變量的轉義等變得⾮常複雜。
5.禁⽌使⽤分區表。
分區表對分區鍵有嚴格要求;分區表在表變⼤後,執⾏DDL、SHARDING、單表恢復等都變得更加困難。因此
禁⽌使⽤分區表,並建議業務端⼿動SHARDING。
6.建議使⽤UNSIGNED存儲⾮負數值。
同樣的字節數,⾮負存儲的數值範圍更⼤。如TINYINT有符號爲 -128-127,⽆符號爲0-255。
7.建議使⽤INT UNSIGNED存儲IPV4。 ⽤UNSINGED INT存儲IP地址佔⽤4字節,CHAR(15)則佔⽤15字節。另外,計算機處理整數類型⽐字符串類
型快。使⽤INT UNSIGNED⽽不是CHAR(15)來存儲IPV4地址,通過MySQL函數inet_ntoa和inet_aton來進⾏
轉化。IPv6地址⺫前沒有轉化函數,需要使⽤DECIMAL或兩個BIGINT來存儲。例如:
SELECT INET_ATON('209.207.224.40'); 3520061480
SELECT INET_NTOA(3520061480); 209.207.224.40
8.強烈建議使⽤TINYINT來代替ENUM類型。
ENUM類型在需要修改或增加枚舉值時,需要在線DDL,成本較⾼;ENUM列值如果含有數字類型,可能會引
起默認值混淆。【ENUM類型說明】
9.使⽤VARBINARY存儲⼤⼩寫敏感的變⻓字符串或⼆進制內容。
VARBINARY默認區分⼤⼩寫,沒有字符集概念,速度快。
10.INT類型固定佔⽤4字節存儲,例如INT(4)僅代表顯⽰字符寬度爲4位,不代表存儲⻓度。
數值類型括號後⾯的數字只是表⽰寬度⽽跟存儲範圍沒有關係,⽐如INT(3)默認顯⽰3位,空格補⻬,超出時
正常顯⽰,python、java客戶端等不具備這個功能。
11.區分使⽤DATETIME和TIMESTAMP。存儲年使⽤YEAR類型。存儲⽇期使⽤DATE類型。 存
儲時間(精確到秒)建議使⽤TIMESTAMP類型。
DATETIME和TIMESTAMP都是精確到秒,優先選擇TIMESTAMP,因爲TIMESTAMP只有4個字節,⽽
DATETIME8個字節。同時TIMESTAMP具有⾃動賦值以及⾃動更新的特性。注意:在5.5和之前的版本中,如
果⼀個表中有多個timestamp列,那麼最多隻能有⼀列能具有⾃動更新功能。
如何使⽤TIMESTAMP的⾃動賦值屬性?
a)⾃動初始化,⽽且⾃動更新: column1 TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE 
CURRENT_TIMESTAMP
b)只是⾃動初始化: column1 TIMESTAMP DEFAULT CURRENT_TIMESTAMP
c)⾃動更新,初始化的值爲0: column1 TIMESTAMP DEFAULT 0 ON UPDATE CURRENT_TIMESTAMP
d)初始化的值爲0: column1 TIMESTAMP DEFAULT 0 【TIMESTAMP字段類型初始化】 
12.所有字段均定義爲NOT NULL。
a)對錶的每⼀⾏,每個爲NULL的列都需要額外的空間來標識。
b)B樹索引時不會存儲NULL值,所以如果索引字段可以爲NULL,索引效率會下降。
c)建議⽤0、特殊值或空串代替NULL值。

9、默認約定說明
1.將⼤字段、訪問頻率低的字段拆分到單獨的表中存儲,分離冷熱數據。
有利於有效利⽤緩存,防⽌讀⼊⽆⽤的冷數據,較少磁盤IO,同時保證熱數據常駐內存提⾼緩存命中率。 

2.禁⽌在數據庫中存儲明⽂密碼。
採⽤加密字符串存儲密碼,並保證密碼不可解密,同時採⽤隨機字符串加鹽保證密碼安全。防⽌數據庫數據被
公司內部⼈員或⿊客獲取後,採⽤字典攻擊等⽅式暴⼒破解⽤戶密碼。

3.表必須有主鍵,推薦使⽤UNSIGNED⾃增列作爲主鍵。
表沒有主鍵,INNODB會默認設置隱藏的主鍵列;沒有主鍵的表在定位數據⾏的時候⾮常困難,也會降低基於
⾏複製的效率。
4.禁⽌冗餘索引。
索引是雙刃劍,會增加維護負擔,增⼤IO壓⼒。(a,b,c)、(a,b),後者爲冗餘索引。可以利⽤前綴索引來達到
加速目的,減輕維護負擔。
5.禁⽌重複索引。
primary key a;uniq index a;重複索引增加維護負擔、佔⽤磁盤空間,同時沒有任何益處。
6.不在低基數列上建⽴索引,例如“性別”。
⼤部分場景下,低基數列上建⽴索引的精確查找,相對於不建⽴索引的全表掃描沒有任何優勢,⽽且增⼤了IO
負擔。
7.合理使⽤覆蓋索引減少IO,避免排序。
覆蓋索引能從索引中獲取需要的所有字段,從⽽避免回表進⾏⼆次查找,節省IO。 INNODB存儲引擎中,
secondary index(⾮主鍵索引,⼜稱爲輔助索引、⼆級索引)沒有直接存儲⾏地址,⽽是存儲主鍵值。如果⽤
戶需要查詢secondary index中所不包含的數據列,則需要先通過secondary index查找到主鍵值,然後再通
過主鍵查詢到其他數據列,因此需要查詢兩次。覆蓋索引則可以在⼀個索引中獲取所有需要的數據,因此效率
較⾼。主鍵查詢是天然的覆蓋索引。例如SELECT email,uid FROM user_email WHERE uid=xx,如果uid
不是主鍵,適當時候可以將索引添加爲index(uid,email),以獲得性能提升。
8.⽤IN代替OR。SQL語句中IN包含的值不應過多,應少於1000個。
IN是範圍查找,MySQL內部會對IN的列表值進⾏排序後查找,⽐OR效率更⾼。
9.表字符集使⽤UTF8,必要時可申請使⽤UTF8MB4字符集。
a)UTF8字符集存儲漢字佔⽤3個字節,存儲英⽂字符佔⽤⼀個字節。
b)UTF8統⼀⽽且通⽤,不會出現轉碼出現亂碼⻛險。
c)如果遇到EMOJ等表情符號的存儲需求,可申請使⽤UTF8MB4字符集。
10.⽤UNION ALL代替UNION。
UNION ALL不需要對結果集再進⾏排序。
11.禁⽌使⽤order by rand()。
order by rand()會爲表增加⼀個僞列,然後⽤rand()函數爲每⼀⾏數據計算出rand()值,然後基於該⾏排序,
這通常都會⽣成磁盤上的臨時表,因此效率⾮常低。建議先使⽤rand()函數獲得隨機的主鍵值,然後通過主鍵
獲取數據。
12.建議使⽤合理的分⻚⽅式以提⾼分⻚效率。
假如有類似下⾯⾯分⻚⻚語句:
SELECT * FROM table ORDER BY TIME DESC LIMIT 10000,10; 這種分⻚⻚⽅⽅式會導致⼤⼤量的io,因
爲MySQL使⽤⽤的是提前讀取策略。
推薦分⻚⻚⽅⽅式:
SELECT * FROM table WHERE TIME<last_TIME ORDER BY TIME DESC LIMIT 10.
SELECT * FROM table inner JOIN (SELECT id FROM table ORDER BY TIME LIMIT 10000,10) as t 
USING(id)
13.SELECT只獲取必要的字段,禁⽌使⽤SELECT *。
減少⺴絡帶寬消耗;
能有效利⽤覆蓋索引;
表結構變更對程序基本⽆影響。
14.SQL中避免出現now()、rand()、sysdate()、current_user()等不確定結果的函數。
語句級複製場景下,引起主從數據不⼀致;不確定值的函數,產⽣的SQL語句⽆法利⽤QUERY CACHE。 

15.採⽤合適的分庫分表策略。例如千庫⼗表、⼗庫百表等。
採⽤合適的分庫分表策略,有利於業務發展後期快速對數據庫進⾏⽔平拆分,同時分庫可以有效利⽤MySQL
的多線程複製特性。
16.減少與數據庫交互次數,儘量採⽤批量SQL語句。
使⽤下⾯的語句來減少和db的交互次數: 
a)INSERT ... ON DUPLICATE KEY UPDATE 
b)REPLACE INTO
c)INSERT IGNORE
d)INSERT INTO VALUES() 
17.拆分複雜SQL爲多個⼩SQL,避免⼤事務。
簡單的SQL容易使⽤到MySQL的QUERY CACHE;減少鎖表時間特別是MyISAM;可以使⽤多核 CPU。【返
回】
18.對同⼀個表的多次alter操作必須合併爲⼀次操作。
mysql對錶的修改絕⼤部分操作都需要鎖表並重建表,⽽鎖表則會對線上業務造成影響。爲減少這種影響,必
須把對錶的多次alter操作合併爲⼀次操作。例如,要給表t增加⼀個字段b,同時給已有的字段aa建⽴索引,
通常的做法分爲兩步:
alter table t add column b varchar(10);
然後增加索引:
alter table t add index idx_aa(aa);
正確的做法是:
alter table t add column b varchar(10),add index idx_aa(aa);
19.避免使⽤存儲過程、觸發器、視圖、⾃定義函數等。
這些⾼級特性有性能問題,以及未知BUG較多。業務邏輯放到數據庫會造成數據庫的DDL、SCALE OUT、
SHARDING等變得更加困難。
20.禁⽌有super權限的應⽤程序賬號存在。
安全第⼀。super權限會導致read only失效,導致較多詭異問題⽽且很難追蹤。
21.提交線上建表改表需求,必須詳細註明涉及到的所有SQL語句(包括INSERT、DELETE、
UPDATE),便於DBA進⾏審覈和優化。
並不只是SELECT語句需要⽤到索引。UPDATE、DELETE都需要先定位到數據才能執⾏變更。因此需要業務提
供所有的SQL語句便於DBA審覈。
22.不要在MySQL數據庫中存放業務邏輯。
數據庫是有狀態的服務,變更復雜⽽且速度慢,如果把業務邏輯放到數據庫中,將會限制業務的快速發展。建
議把業務邏輯提前,放到前端或中間邏輯層,⽽把數據庫作爲存儲層,實現邏輯與存儲的分離。
23.建表語句⽰例

 

24.產品線對應名稱說明(供參考)

事業部 命名簡寫
機票 f
度假 vc
酒店 h
旅⾏ lv
⽆線 wap
⻔票 tkt
兜⾏ dx
旅圖 lvtu
搜索 s
ops  ops
⽀付平臺 pay
dba dba
qss qss
⽕⻋票 t
特殊項目部 sp
呼叫中⼼ cc
⽤戶中⼼ uc
市場部  mkt

--------------------------------------

版權聲明:本文爲【PythonJsGo】博主的原創文章,轉載請附上原文出處鏈接及本聲明。

博主主頁:https://my.oschina.net/u/3375733

本篇文章同步在個人公衆號:

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