數(shù)據(jù)庫表設(shè)計(jì)太劣質(zhì),被領(lǐng)導(dǎo)瘋狂diss
本文轉(zhuǎn)載自微信公眾號(hào)「Java極客技術(shù)」,作者鴨血粉絲。轉(zhuǎn)載本文請(qǐng)聯(lián)系Java極客技術(shù)公眾號(hào)。
在大家開發(fā)的時(shí)候,很多時(shí)候不是說,有人告訴你已經(jīng)完全的設(shè)計(jì)好數(shù)據(jù)庫了,也沒有專門的人去管理數(shù)據(jù)庫表設(shè)計(jì)這塊的內(nèi)容,而阿粉的朋友就是這么悲催,接手了公司一個(gè)同事的一個(gè)比較重要的功能,而阿粉的朋友也沒有重新進(jìn)行設(shè)計(jì),于是就出現(xiàn)了這樣的一幕。
你設(shè)計(jì)的這是啥?
領(lǐng)導(dǎo):你數(shù)據(jù)庫設(shè)計(jì)的軟刪除呢?Delete 就直接給我刪了?萬一到時(shí)候用戶反悔了,想查詢某項(xiàng)數(shù)據(jù)怎么辦?
我:........(內(nèi)心OS:這特么不是我設(shè)計(jì)的好不)
領(lǐng)導(dǎo):你趕緊給我加上這個(gè),我給你講講需求,你看他之前做了多少了,把沒做的功能都給我補(bǔ)上。
我:.........好的(內(nèi)心OS:我擦,他做了這么久的功能就做了這么一丟丟,你讓我抓緊時(shí)間做完,你是傻子么?)
領(lǐng)導(dǎo):你看這,兩個(gè)表的關(guān)聯(lián)字段,竟然不是相同類型的,你不用相同的名字就不用吧,你類型不一樣,怎么能行,你趕緊去統(tǒng)一一下。
我:.........(這明明不是我設(shè)計(jì)的表好不好,這種低智商的行為,是我能干出來的事情么?)
但是阿粉朋友在向阿粉抱怨的時(shí)候,就表示心態(tài)已經(jīng)被影響了,明明不是自己的鍋,結(jié)果這鍋到最后全都是自己來背,不過想想也是,畢竟如果要是這個(gè)功能非常好做的話,那同事為啥辭職。阿粉接下來就說說這個(gè)數(shù)據(jù)庫表的設(shè)計(jì),到底是怎么設(shè)計(jì)才能更好呢?
數(shù)據(jù)庫表設(shè)計(jì)遵循原則
數(shù)據(jù)庫表設(shè)計(jì)范式
(1). 第一范式(確保每列保持原子性)
這是什么意思呢?你如果去百度上搜索,結(jié)果就是所有字段值都是不可分解的原子值。就這話,云里霧里的有點(diǎn)難理解呀,這種情況我們就得自己去想想有沒有什么現(xiàn)實(shí)生活中的案例,比如說,我們?cè)诒4婺承┑刂沸畔⒌臅r(shí)候,一般我們都是采用,省市區(qū),然后再加上具體的位置來表示完整的地址,很少有人會(huì)在數(shù)據(jù)庫中直接設(shè)計(jì)一個(gè)地址的字段,再比如我說我們?cè)O(shè)計(jì)商品的時(shí)候,都是商品,數(shù)量,價(jià)格,而不是設(shè)計(jì)成商品1,商品2,商品3,數(shù)量1,數(shù)量2,數(shù)量3.
而數(shù)據(jù)庫的第一范式也就是 1NF,實(shí)際上不單單是保證每一列的原子性,還有如果兩列的屬性相近或相似或一樣,盡量合并屬性一樣的列,確保不產(chǎn)生冗余數(shù)據(jù)。
這就是阿粉上面說的那個(gè)商品的案例。
(2).第二范式
在一個(gè)數(shù)據(jù)庫表中,一個(gè)表中只能保存一種數(shù)據(jù),不可以把多種數(shù)據(jù)保存在同一張數(shù)據(jù)庫表中。
每一行的數(shù)據(jù)只能與其中一列相關(guān),即一行數(shù)據(jù)只做一件事。只要數(shù)據(jù)列中出現(xiàn)數(shù)據(jù)重復(fù),就要把表拆分開來。
上面這句話感覺好像有點(diǎn)多此一舉的樣子,相同的數(shù)據(jù)信息在一般人的設(shè)計(jì)中,是不會(huì)出現(xiàn)在同一張表中的,因?yàn)楫吘谷绻承┳侄我恢笔侵貜?fù)的,數(shù)據(jù)量多不說,關(guān)聯(lián)的時(shí)候也會(huì)出現(xiàn)左也不行,又也不行,就會(huì)出現(xiàn)寫SQL出現(xiàn)各種問題的情況。
(3).第三范式
數(shù)據(jù)不能存在傳遞關(guān)系,即每個(gè)屬性都跟主鍵有直接關(guān)系而不是間接關(guān)系。阿粉之前接收過一個(gè)項(xiàng)目,就是出現(xiàn)了 A 指向 B,B 指向 C,加入說我們現(xiàn)在有一張訂單表,我們訂單表中肯定要有人員的信息,而我們又會(huì)有一張人員信息表中的Id與訂單表中的人員信息對(duì)應(yīng),這時(shí)候,訂單表中就盡可能的不要存在人員的其他相關(guān)的信息了,比如說姓名,身份證號(hào),等等信息。
而這時(shí)候,我們?cè)讷@取訂單信息的時(shí)候,直接通過當(dāng)前用戶的ID,就可以查詢出所有對(duì)應(yīng)的訂單,那些所有的人員信息全部都包含在了人員信息表中。
說到這里,阿粉實(shí)際上想說,數(shù)據(jù)庫三范式,只是說是一個(gè)原則,而不是非要遵守的原則,因?yàn)橛行r(shí)候,很多在建表的時(shí)候,都是根據(jù)我們的需求來進(jìn)行制定。
范式也有優(yōu)缺點(diǎn):
設(shè)計(jì)數(shù)據(jù)表的時(shí)候,其實(shí)范式的優(yōu)點(diǎn)很明顯,避免數(shù)據(jù)冗余,減少維護(hù)數(shù)據(jù)完整性的麻煩,減少數(shù)據(jù)庫的空間,數(shù)據(jù)變更速度快
但是缺點(diǎn)也是一樣的明顯,按照范式的規(guī)范設(shè)計(jì)的表,等級(jí)越高的范式設(shè)計(jì)出來的表數(shù)量越多,獲取數(shù)據(jù)時(shí),表關(guān)聯(lián)過多,性能較差。
阿粉之前見過一個(gè)很早之前的項(xiàng)目,一個(gè)醫(yī)療系統(tǒng),設(shè)計(jì)的表大概超過有2000個(gè)表,阿粉當(dāng)時(shí)都滿臉的震驚。
據(jù)說是一個(gè)很早之前的程序員設(shè)計(jì)的,當(dāng)時(shí)是嚴(yán)格遵守了范式來進(jìn)行的數(shù)據(jù)庫的設(shè)計(jì),結(jié)果可想而知。一個(gè)SQL查詢,關(guān)聯(lián)那么多的表,效率能高到哪里去呢?
學(xué)會(huì)通過需求來進(jìn)行定制
大家還記得阿粉之前寫過的用UUID生成主鍵,被diss么?
比如之前的對(duì)比,數(shù)據(jù)庫自增,雪花算法生成ID,和UUID生成ID,這三個(gè)的對(duì)比,結(jié)果100w條數(shù)據(jù),最終勝出的還是雪花算法,大家對(duì)這個(gè)有興趣的可以去看一下這篇文章。
使用uuid作為數(shù)據(jù)庫主鍵,被技術(shù)總監(jiān)懟了一頓!
為什么說要學(xué)會(huì)通過需求來進(jìn)行定制,因?yàn)槭紫任覀円宄銓懙臇|西,最后實(shí)際的落腳點(diǎn),都是需求,實(shí)現(xiàn)了這個(gè)需求,在不出現(xiàn)任何意外的情況下,永遠(yuǎn)都是需求放在第一位,如果你把一個(gè)簡(jiǎn)單的一對(duì)多的關(guān)系,非要拆分成一個(gè)多對(duì)多的關(guān)系,這完全就是多此一舉的事情。
而這種通過需求來進(jìn)行定制的,實(shí)際上就可以稱之為反范式。
而反范式設(shè)計(jì)同樣的也是優(yōu)缺點(diǎn)明顯,業(yè)務(wù)場(chǎng)景中需要的數(shù)據(jù)幾乎都可以在一張表上顯示,數(shù)據(jù)冗余了。
但是它提高了業(yè)務(wù)響應(yīng)的時(shí)間,現(xiàn)在為什么有些中間件的存在,就是因?yàn)殡S著公司業(yè)務(wù)的拓展,數(shù)據(jù)量的增多,有時(shí)候一個(gè)表中的數(shù)據(jù)超過百萬,甚至千萬,當(dāng)你寫一個(gè)NOT IN 的時(shí)候,你就會(huì)發(fā)現(xiàn),一秒,兩秒,三秒....時(shí)間就這么過去了。
阿里開發(fā)手冊(cè)
實(shí)際上阿粉之前也專門研究過一段時(shí)間的阿里開發(fā)手冊(cè),比如:
【強(qiáng)制】:表達(dá)是否概念的時(shí)候,必須使用is_xxx的方式來進(jìn)行命名,數(shù)據(jù)類型使用unsigned tinyint (1,表示是,0表示否)
比如如果你在數(shù)據(jù)庫的表中設(shè)計(jì)軟刪除的概念,你選擇使用is_delete 還是會(huì)選擇使用 deleted 這種,實(shí)際上百分之60以上的是會(huì)使用 is_delete,而設(shè)計(jì)這種 deleted 的,一般很多都是剛?cè)胄胁痪玫哪贻p人,對(duì)字段設(shè)計(jì)沒有什么概念的。
【強(qiáng)制】:表名稱不使用復(fù)數(shù)名詞,比如說我們的活動(dòng)Activity,你如果把它設(shè)計(jì)Activities,當(dāng)你在建立實(shí)體類的時(shí)候 Activity 和 Activities 是不是感覺就不一樣,第二個(gè)看著就總是有些難受。
大家如果有興趣的,可以在公眾號(hào)回復(fù) 阿里 獲取泰山版 阿里巴巴開發(fā)手冊(cè)。
關(guān)于數(shù)據(jù)庫設(shè)計(jì),你還想知道些什么?