隨著工作經(jīng)驗(yàn)的積累,我日益感覺(jué)到,對(duì)一名程序員來(lái)說(shuō),擁有良好的數(shù)據(jù)庫(kù)設(shè)計(jì)能力是很重要的,甚至是最重要的。
程序員界有一句著名的話
Talk is cheap, show me the code
把這句話演變一下,就成了
Code is boring, show me the data structure
數(shù)據(jù)庫(kù)的種類很多,對(duì)于像作者這樣的web后端程序員來(lái)說(shuō),可以把范圍縮小到關(guān)系型數(shù)據(jù)庫(kù)、非關(guān)系型數(shù)據(jù)庫(kù)與NoSQL數(shù)據(jù)庫(kù)。
數(shù)據(jù)結(jié)構(gòu)為何如此重要
一切代碼都是圍繞數(shù)據(jù)結(jié)構(gòu)運(yùn)行的。
客戶端展現(xiàn)的動(dòng)態(tài)數(shù)據(jù),都是存儲(chǔ)在數(shù)據(jù)庫(kù)中,這對(duì)程序員來(lái)說(shuō)一定是常識(shí)了。拿你正在瀏覽的這個(gè)頁(yè)面為例,文章的作者、標(biāo)題、正文、評(píng)論、喜歡等等,只要你打開(kāi)任意兩篇文章,兩個(gè)頁(yè)面不一樣的地方,幾乎都是因?yàn)樵跀?shù)據(jù)庫(kù)中存儲(chǔ)的內(nèi)容不同。
良好的數(shù)據(jù)結(jié)構(gòu)可以提升性能,使代碼變得簡(jiǎn)單、清晰。數(shù)據(jù)結(jié)構(gòu)清晰了,圍繞著數(shù)據(jù)運(yùn)行的代碼自然就清晰了。
數(shù)據(jù)庫(kù)設(shè)計(jì)需考慮的因素
提到數(shù)據(jù)庫(kù)設(shè)計(jì)原則,首先會(huì)想到第一、第二、第三范式,這些理論能了解最好,但這不是本文探討的主題。
面對(duì)一個(gè)具體的應(yīng)用場(chǎng)景,設(shè)計(jì)數(shù)據(jù)庫(kù)時(shí)應(yīng)考慮哪些因素?為了能夠言之有物,我們拿簡(jiǎn)書(shū)的文章頁(yè)面來(lái)現(xiàn)身說(shuō)法。
當(dāng)前可用性
數(shù)據(jù)結(jié)構(gòu)的設(shè)計(jì)要能達(dá)到應(yīng)用場(chǎng)景的要求,這是最基本的。舉個(gè)例子,這篇文章的正文存儲(chǔ)在了數(shù)據(jù)表中的某個(gè)字段,該字段的長(zhǎng)度被設(shè)定為1000字,這顯然不能滿足應(yīng)用場(chǎng)景的要求,文章寫到這里已經(jīng)超過(guò)了1000字(估計(jì)的,我沒(méi)有數(shù))。
適當(dāng)超前
超前到什么程度需要根據(jù)對(duì)應(yīng)用的預(yù)期來(lái)定。拿QQ來(lái)說(shuō),馬化騰最初肯定預(yù)見(jiàn)不到QQ能有目前的用戶量與活躍度,畢竟那是近20年前的事情了。
對(duì)于本文設(shè)定的應(yīng)用場(chǎng)景,我們把超前設(shè)定為網(wǎng)站的文章數(shù)量達(dá)到了千萬(wàn)級(jí)。這時(shí)如果只把文章存在一張數(shù)據(jù)表里,讀寫性能必然是會(huì)急劇下降的,這必然會(huì)導(dǎo)致用戶體驗(yàn)變差,用戶流失。老板不能容忍,DBA也不能容忍。
合理的解決方案之一是分為兩張數(shù)據(jù)表,一張存儲(chǔ)熱門文章,另一張存儲(chǔ)非熱門文章。畢竟熱門文章占少數(shù),熱門文章的加載速度相對(duì)就更快了。還有別的解決方案嗎?肯定有,留給您自己思考。
分離易變與不易變部分
對(duì)于一篇文章來(lái)說(shuō),哪些是易變的,哪些是不易變(不變)的?
不易變(不變)
作者
標(biāo)題
正文(字?jǐn)?shù))
發(fā)布時(shí)間
更新時(shí)間
易變
閱讀次數(shù)
評(píng)論
喜歡該文章的用戶與數(shù)量
拆分的好處在于,首先數(shù)據(jù)結(jié)構(gòu)更清晰了,其次可以提高讀寫性能,當(dāng)文章有了新評(píng)論,只需更新存放評(píng)論的數(shù)據(jù)表。如果不拆分,需要更新的記錄占用的磁盤空間很大,這對(duì)磁盤IO速度是個(gè)考驗(yàn)。
對(duì)于拆分出的部分,可以繼續(xù)運(yùn)用這些原則進(jìn)行設(shè)計(jì)。
應(yīng)對(duì)可能出現(xiàn)的新需求
互聯(lián)網(wǎng)應(yīng)用的迭代周期很短,設(shè)計(jì)數(shù)據(jù)結(jié)構(gòu)時(shí)應(yīng)考慮到可能出現(xiàn)的新需求。拿喜歡該文章的用戶與數(shù)量舉例。
為了達(dá)到應(yīng)用的要求,最簡(jiǎn)單的方式是將這些用戶放在一條記錄里,存儲(chǔ)的字段可以是數(shù)組類型。這樣設(shè)計(jì),喜歡文章的用戶信息與用戶數(shù)量都能輕易獲取,讀寫性能也很好。
某天,產(chǎn)品經(jīng)理找到了你:“商量個(gè)新需求唄”,在文章下方加個(gè)模塊,就叫“喜歡該文章的人還喜歡了”。你就懵逼了,沒(méi)法破,除非重新設(shè)計(jì)數(shù)據(jù)結(jié)構(gòu),然后就帶來(lái)了遷移數(shù)據(jù)一系列事情。其實(shí)這個(gè)需求挺合理的,說(shuō)得高大上一點(diǎn),這叫“精準(zhǔn)推薦”。
很明顯,將用戶放在數(shù)組里只能支持“查詢喜歡某文章的用戶”,不支持“查詢某用戶喜歡的文章”。
適當(dāng)?shù)娜哂?/p>
或許你已經(jīng)注意到了,文章的標(biāo)題下面有這篇文章的字?jǐn)?shù)。計(jì)算文章的字?jǐn)?shù),有兩個(gè)時(shí)機(jī):
保存文章時(shí)
讀取文章時(shí)
后者的優(yōu)勢(shì)在于數(shù)據(jù)表中少了一個(gè)字段,而且這個(gè)字段不是必需的。哪個(gè)時(shí)機(jī)更好?個(gè)人覺(jué)得前者更好,理由如下:
計(jì)算長(zhǎng)篇文章的字?jǐn)?shù)是比較耗時(shí)的,應(yīng)盡量減少計(jì)算次數(shù)
總體來(lái)看,文章的保存次數(shù)遠(yuǎn)小于讀取次數(shù)
如果能夠提高應(yīng)用的性能,適當(dāng)?shù)娜哂嗍潜匾摹?/p>
結(jié)尾
本文總結(jié)了設(shè)計(jì)數(shù)據(jù)庫(kù)時(shí)需遵守的幾個(gè)原則
可用性
適當(dāng)超前
應(yīng)對(duì)新需求
分離易變與不易變部分
適當(dāng)冗余
因?yàn)樽灾€未達(dá)到數(shù)據(jù)庫(kù)專家的水準(zhǔn),寫出的內(nèi)容肯定有不準(zhǔn)確的地方,歡迎批評(píng)指正。
寫這篇文章的想法醞釀很久了,但一直沒(méi)時(shí)間動(dòng)筆。適逢中秋佳節(jié),上海下著大雨,不便出門行走,便安坐在電腦前敲下了這千八百字,前后花了兩個(gè)多小時(shí)。如果喜歡就點(diǎn)贊,能指出不足或提出意見(jiàn)就更好了。