1. 統(tǒng)一的規(guī)范
首先,我們來一些通用的規(guī)范。這里有很多是經(jīng)驗(yàn)值,如果你的數(shù)據(jù)庫所在的宿主機(jī)硬件,并不是十分的牛X,可以考慮再降低一下標(biāo)準(zhǔn)。
存儲引擎: 請統(tǒng)一使用innodb存儲引擎,特殊的數(shù)據(jù)庫引擎必須通過DBA的評審。
字符集:統(tǒng)一使用utf8字符集。這個要從應(yīng)用程序、服務(wù)器、數(shù)據(jù)庫的表、字段等全部統(tǒng)一起來。注意:MySQL中的utf8mb4
字符集,才是真正的utf8,請用這個。
作用范圍:不要在MySQL存儲大對象,比如圖片、音樂等;不要用MySQL做Gis運(yùn)算、全文檢索;不使用存儲過程、觸發(fā)器、函數(shù)、外鍵,避免破壞數(shù)據(jù)庫的性能和擴(kuò)展性。
使用上限:
- 每個MySQL實(shí)例,數(shù)據(jù)庫不要超過50個;
- 單數(shù)據(jù)庫容量,不要超過500GB,否則分庫;
- 單表記錄數(shù)量,不要超過5000W,否則分表;
- 單表子段數(shù)量,不要超過30個,否則拆表;
- 單張表中索引數(shù)量不超過5個,單個索引中的字段數(shù)不超過5個;
- varchar字段最大值不超過1024;注意:VARCHAR(N)中的N表示字符數(shù)而非字節(jié)數(shù)
2. 索引規(guī)范
索引是數(shù)據(jù)庫中非常重要的結(jié)構(gòu),可以加速數(shù)據(jù)的檢索。但索引是要占用大量空間的,如果你的數(shù)據(jù)表里面沒幾條記錄,就不必創(chuàng)建索引。比如2000條以下。
選擇性很小的字段(低基數(shù)列),不要加索引。比如一些state,type,布爾判斷等。因?yàn)榧恿艘矝]用。
盡量讓索引的內(nèi)容盡量的短!比較長的子段,要使用前綴索引。比如:title varchar (64)
,可以創(chuàng)建前綴索引 idx_title (title(16))
。
合理利用索引的最左原則,合并相似的索引。比如 (a) (ab) (abc)三種索引需求,我們只需要創(chuàng)建abc這一個索引就ok了。
避免在索引列做計(jì)算(這將造成索引失效),比如 data_format(created_date)
,substring(short_name,0,6) = 'xjjdog'
。
不能使用%
前綴模糊查詢,因?yàn)闊o法使用索引,例如:WHERE name LIKE '%味道'
。
不能使用數(shù)據(jù)庫端做全文檢索操作。雖然它支持,也不要這么做。
索引的命名要有章可循:idx_
前綴表明是普通索引,而 uk_
前綴表明的是唯一索引。
- SQL規(guī)范
建議在每個表中,添加下面三個字段。其實(shí),SpringBoot JPA,也建議你添加上這三個字段。根據(jù)時間字段,除了審計(jì),還能夠做一些非常nice的遷移操作;version字段是高并發(fā)下的樂觀鎖實(shí)現(xiàn),UPDATE語句可以結(jié)合version字段,避免并發(fā)操作造成的不一致情況。
- created:記錄創(chuàng)建時間,時間類型
- modified:記錄修改時間,時間類型
- version:“樂觀鎖”的版本標(biāo)記,long型,默認(rèn)為0
大多數(shù)字段應(yīng)該定義成not null
的,并分配默認(rèn)值,但是不要default null
,因?yàn)閿?shù)據(jù)庫無法索引null值。
復(fù)雜的SQL查詢語句,是絕對要避免的。我們所說的,就是慢查詢。慢查詢會占用大量資源,并阻塞線程,應(yīng)該見諒將大SQL拆分成多條簡單的SQL,減少數(shù)據(jù)的鎖定時間。
另外,不要在不同數(shù)據(jù)類型的字段上進(jìn)行比較,避免字段類型轉(zhuǎn)換造成性能損失,這就要求我們在SQL語句中傳入的參數(shù)類型,和數(shù)據(jù)庫中所定義的類型是相同的。
禁止使用select *
進(jìn)行輸出,應(yīng)該選擇具體的字段進(jìn)行輸出。除了避免無用的字段造成傳輸上的性能損耗,還能在一定程度上避免敏感信息的泄漏。
SQL中避免出現(xiàn)now()、rand()、sysdate()、current_user()等不確定結(jié)果的函數(shù)。
禁止使用order by rand()。
插入語句,不要直接使用 nsert into table values(),而應(yīng)該加入具體的字段,否則無法適應(yīng)數(shù)據(jù)庫變更情況。在做批量插入時,一次性操作100-200條就可以,沒必要把batch數(shù)量設(shè)置成上千上萬。
禁止非框架類業(yè)務(wù)代碼,直接調(diào)用set sql_mode
或者set tx_isolation
,禁止使用SELECT … FOR UPDAT
,優(yōu)先采用樂觀鎖實(shí)現(xiàn)。
多表關(guān)聯(lián)不要超過3個,盡量拆分成簡單的SQL處理。
大多數(shù)開發(fā)人員會在需要時寫UNION,這往往會導(dǎo)致執(zhí)行一個排序來消除重復(fù)。應(yīng)該盡量使用UNION ALL來代替UNION。
注意OR語句的一些改善情況。比如WHERE id=1 OR id=2
可以 改寫為WHERE id IN(1,2)
。在不同的字段,可以將OR改寫為UNION ALL
。
4. 命名規(guī)范
數(shù)據(jù)庫表和字段的命名,不要使用駝峰命名方式。比如,不能叫saleOrder
,而應(yīng)該叫做sale_order
。因?yàn)榇蠖鄶?shù)數(shù)據(jù)庫,都不區(qū)分大小寫,下劃線命名會更安全。
這些命名,只能使用英文小寫字母、數(shù)字和下劃線,長度不超過17個字符。
命名應(yīng)該有確切的含義。和代碼規(guī)范一樣,不允許使用a,b等無意義的字符串。不允許中文拼音縮寫、中英文混用等。
嚴(yán)禁出現(xiàn)哥哥表和妹妹字段。
5. 安全安全安全
(1) 服務(wù)器隔離 如果你的公司有多個環(huán)境,比如dev環(huán)境,測試環(huán)境等,就要做好相應(yīng)的隔離。比如,不允許在線上環(huán)境直接進(jìn)行開發(fā)和測試、禁止在線上做數(shù)據(jù)庫壓?力測試。這是非常重要的,避免了無謂的數(shù)據(jù)錯亂。如果條件允許,甚至可以做物理隔離,用不同的IP段進(jìn)行區(qū)分。不長腦子的程序員有很多,你永遠(yuǎn)不知道他們連的是哪個環(huán)境的數(shù)據(jù)庫。
(2)賬戶的權(quán)限 永遠(yuǎn)不要在生產(chǎn)上,讓root賬號遠(yuǎn)程可連。對不同的應(yīng)用,應(yīng)該分配不同的database,并建立相互隔離的賬號。
賬號默認(rèn)開啟select/insert/update/delete/execute的權(quán)限就可以。create都不能放開,用根本上杜絕程序員們刪庫跑路的機(jī)會。
針對安全級別高的應(yīng)用,應(yīng)分配讀寫賬號。讀賬號去掉各種更新權(quán)限,只能做一些sql查詢。賬號命名方式上,可以加入_w
或者_r
后綴,表明它們的意圖。
對于SQL的傳入?yún)?shù)(數(shù)字,字符和混用)必須進(jìn)行合法性檢查,防止SQL注入。業(yè)務(wù)應(yīng)該提前準(zhǔn)備好風(fēng)險SQL語句,進(jìn)行集中審核,負(fù)責(zé)后果自負(fù)。
6. 性能小case
如有自增字段,請使用無符號型(unsigned)int或bigint 。優(yōu)先使用更小的數(shù)據(jù)類型,比如:
- 數(shù)字用tinyint、smallint、mediumint、int、bigint類型;
- 日期用date、datetime類型;
- 時間用timestamp、int類型;
- 不使用char、varchar存儲日期和時間;
- 使用更小的數(shù)據(jù)類型,能用tinyint的就不用smallint,能用timestamp的就不用datetime類型;
不能使用tinyblob、mediumblob、blob和longblob類型字段,對于表存在大字段類型,應(yīng)當(dāng)考慮單獨(dú)拆分。
OLTP數(shù)據(jù)庫絕對要避免大事務(wù)和數(shù)據(jù)庫端運(yùn)算,可以考慮使用NoSQL或者大數(shù)據(jù)計(jì)算平臺。