如果你是伴隨著結(jié)構(gòu)化數(shù)據(jù)庫成長起來的,請(qǐng)舉手刻恭!你是否接觸過SQL瞧省?也許在學(xué)校的時(shí)候使用過MS Access,而后在工作中涉獵過MySQL鳍贾。
在數(shù)據(jù)庫管理系統(tǒng)中臀突,SQL作為主角已經(jīng)有很多年的歷史了。如果你是個(gè)專業(yè)的軟件工程師贾漏,那么你很有可能已經(jīng)經(jīng)歷了幾十甚至上百個(gè)基于SQL的項(xiàng)目,而且很有可能是MySQL藕筋,或者M(jìn)SSQL或者PostgreSQL纵散。
雖然SQL有時(shí)會(huì)被詬病速度過慢,過于集中化隐圾,或者僅僅是老舊伍掀,但是不可否認(rèn),SQL很穩(wěn)定暇藏,而且在過去的20年中蜜笤,SQL已經(jīng)成為了大多數(shù)基于web的軟件的核心組成部分。不過近些年來盐碱,NoSQL數(shù)據(jù)庫管理系統(tǒng)也有著顯著的成長趨勢(shì)把兔。
如果你在創(chuàng)業(yè)公司工作,那么這是一個(gè)讓你接觸NoSQL數(shù)據(jù)庫的好機(jī)會(huì)瓮顽。創(chuàng)業(yè)公司通常沒有什么遺留代碼需要支持县好,還會(huì)雇傭年輕上進(jìn)的工程師,鼓勵(lì)他們探索一切能讓它們一下子脫穎而出的會(huì)成為下一個(gè)大事件的技術(shù)暖混。伴隨著近些年技術(shù)創(chuàng)業(yè)公司的興起缕贡,像NoSQL這樣的技術(shù)一定會(huì)取得快速的進(jìn)步。
另外拣播,眾多公有云設(shè)施的到來也加快了NoSQL技術(shù)的應(yīng)用:我們可以使用一些簡單的點(diǎn)擊操作就搭建出一套分布式數(shù)據(jù)庫集群晾咪。然后可以使用像NPM和Composer這樣的工具一樣,迅速的獲得一套簡單易用的SDK贮配。智能IDE可以通過類型提示的功能幫我們編寫一半的代碼谍倦,而如果我們遇到了問題,我們可以從大量的文檔或者有意于推廣相關(guān)技術(shù)的社區(qū)使用者那里尋求幫助牧嫉。
當(dāng)年的那個(gè)最好的服務(wù)來自于最大的公司(當(dāng)然要花錢)剂跟,很少有人敢使用小公司產(chǎn)品的時(shí)代一去不復(fù)返了减途。這也是SQL可以上升到現(xiàn)在這個(gè)高度的原因,而NoSQL也正在做著類似的事情曹洽。
但是僅僅是因?yàn)橐粋€(gè)好的舊技術(shù)(或者一個(gè)時(shí)髦的新技術(shù))能被用于一個(gè)項(xiàng)目中鳍置,就意味著它就應(yīng)該被用于項(xiàng)目中嗎?
選用合適的工具
無論是學(xué)習(xí)一個(gè)新的技術(shù)棧多有樂趣送淆,或者在極短的時(shí)間內(nèi)神奇的搭出一個(gè)原型有多好玩税产,作為職業(yè)軟件工程師,我一向?qū)γつ孔冯S開發(fā)趨勢(shì)持謹(jǐn)慎態(tài)度偷崩。雖然剛開始的時(shí)候每個(gè)東西都會(huì)打上下一個(gè)大事件的標(biāo)簽辟拷,但是大多數(shù)聲稱為下一個(gè)大事件的項(xiàng)目最終都無聲無息的消失了。
在適當(dāng)?shù)臅r(shí)候做正確的判斷是一個(gè)微妙的權(quán)衡阐斜。
SQL支持者能迅速的指出結(jié)構(gòu)化關(guān)系型數(shù)據(jù)的好處衫冻。他們會(huì)拿出20多年來SQL一直活躍的支撐著軟件庫的穩(wěn)定性來作為佐證。
而NoSQL的追隨者則喜歡提出當(dāng)數(shù)據(jù)不再需要依附于模式時(shí)數(shù)據(jù)將獲得的自由度谒出。他們會(huì)強(qiáng)調(diào)使用NoSQL數(shù)據(jù)庫進(jìn)行嵌套數(shù)據(jù)查詢時(shí)查詢能力的提升隅俘。
當(dāng)然,兩個(gè)陣營都對(duì)笤喳。但是同時(shí)又都是錯(cuò)的为居。
一些項(xiàng)目(比如,大多數(shù)的web應(yīng)用)杀狡,擁有非常結(jié)構(gòu)化的數(shù)據(jù)蒙畴。有時(shí)甚至不需要被搜索到;數(shù)字型主鍵就足夠供開發(fā)者查詢記錄呜象。
同樣的膳凝,有些項(xiàng)目會(huì)需要存儲(chǔ)龐大的非結(jié)構(gòu)化數(shù)據(jù),以供以后進(jìn)行分析使用董朝。任何處理日志的工具都屬于這個(gè)類型鸠项。這樣的項(xiàng)目使用一個(gè)SQL數(shù)據(jù)庫是完全沒有用的。
審視一個(gè)項(xiàng)目的用例是非常重要的子姜,請(qǐng)把你的偏見和對(duì)某些技術(shù)棧的個(gè)人喜好拋在一邊祟绊。
中間情況怎么辦?
以上的應(yīng)該是基本共識(shí)。但是如果你的用例哪邊都靠不上怎么辦哥捕?當(dāng)你的項(xiàng)目需要將結(jié)構(gòu)化數(shù)據(jù)存儲(chǔ)在一個(gè)多層嵌套結(jié)構(gòu)(比如牧抽,一個(gè)JSON對(duì)象)里怎么辦?或者當(dāng)你需要分析遥赚、處理非結(jié)構(gòu)化數(shù)據(jù)扬舒,然后再將它存入一個(gè)結(jié)構(gòu)化結(jié)構(gòu)中怎么辦?亦或者做了這些之后還要在子字段的子字段中查詢數(shù)據(jù)怎么辦凫佛?
這些才是要變的混亂不堪的地方讲坎。
你可以將數(shù)據(jù)整理為JSON對(duì)象孕惜,序列化然后存成text類型。近些年的SQL數(shù)據(jù)庫甚至允許你使用JSON字符串進(jìn)行查詢操作晨炕。但是你怎么手動(dòng)的瀏覽這些數(shù)據(jù)衫画?你是否能在這個(gè)數(shù)據(jù)的一個(gè)子集有所變更的時(shí)候,輕松的更新這條數(shù)據(jù)瓮栗?
SQL的主旨是將存儲(chǔ)的數(shù)據(jù)標(biāo)準(zhǔn)化削罩,將數(shù)據(jù)處理為有用的信息,然后把數(shù)據(jù)分離為一些通過外鍵聯(lián)系起來的表费奸。這通常是很有效率的弥激,而且有助于手動(dòng)瀏覽--你可以從數(shù)據(jù)的任一部分開始,根據(jù)表之間的關(guān)聯(lián)進(jìn)行一次數(shù)據(jù)查詢愿阐。
但是怎么對(duì)一個(gè)關(guān)鍵詞進(jìn)行查詢呢微服?你應(yīng)該做一個(gè)包含
查詢,但是一旦你得到了成千上萬條記錄缨历,那計(jì)算代價(jià)將是巨大的职辨。
所以你會(huì)想也許你應(yīng)該把數(shù)據(jù)存放在NoSQL數(shù)據(jù)庫中糊饱。畢竟桃漾,這種事情比較適合由NoSQL數(shù)據(jù)庫來做耸序,對(duì)嗎?
查詢數(shù)據(jù)也許是很容易的觉吭,但是管理數(shù)據(jù)卻是一個(gè)更大的任務(wù)。同時(shí)如果沒有良好定義的表和模式仆邓,當(dāng)你必須深入數(shù)據(jù)庫進(jìn)行手動(dòng)管理時(shí)鲜滩,數(shù)據(jù)庫就像亂成一鍋“文檔湯”。你可能需要在每次查詢時(shí)檢索所有的數(shù)據(jù)节值,而這樣的代價(jià)勢(shì)必是沉重的徙硅。除非你限制返回列,但是這是否說明了一個(gè)問題搞疗,那就是沒有一個(gè)合適的模式供你使用來搞定這件事嗓蘑?另外那些和其他數(shù)據(jù)有關(guān)聯(lián)的數(shù)據(jù)記錄怎么辦?
所以話說回來匿乃,任何一個(gè)都不是可行的桩皿,但是兩個(gè)加在一起似乎是個(gè)可行的解決方案。
解決方案
選擇性的接受這個(gè)建議--畢竟每個(gè)項(xiàng)目的需求都不一樣幢炸。
在很多情況下泄隔,應(yīng)用在檢索和顯示信息上花費(fèi)的時(shí)間要比花在更新信息上的時(shí)間多。我們?cè)诖瞬挥懻摿奶焓一蛘邊^(qū)塊鏈類型的應(yīng)用宛徊,而是標(biāo)準(zhǔn)的網(wǎng)絡(luò)應(yīng)用佛嬉。
首先會(huì)有一個(gè)穩(wěn)定的數(shù)據(jù)來源流逻澳,但是并不需要在數(shù)據(jù)提交后立刻被訪問到。通常數(shù)據(jù)被放在隊(duì)列中暖呕,然后在幾秒鐘后由微服務(wù)來進(jìn)行處理斜做,這是完全可以被接受的。如果程序特別大缰揪,那么這將是程序設(shè)計(jì)的一個(gè)大需求點(diǎn)陨享。
在這種機(jī)制下,可是考慮一下兩種不同的數(shù)據(jù)庫角色钝腺。有一個(gè)內(nèi)部數(shù)據(jù)庫--應(yīng)用和相關(guān)的微服務(wù)與之通訊抛姑,處理那些用戶看不到的工作--和一個(gè)外部數(shù)據(jù)庫--直接反饋用戶的請(qǐng)求。
內(nèi)部數(shù)據(jù)庫應(yīng)該是能被輕松替換的艳狐。它會(huì)被知曉主鍵關(guān)系的內(nèi)部服務(wù)訪問定硝,并且能夠處理高結(jié)構(gòu)化數(shù)據(jù)。外部數(shù)據(jù)庫則需要能應(yīng)對(duì)用戶的任何請(qǐng)求毫目;也許是一個(gè)簡單的關(guān)鍵詞搜索蔬啡,或者是個(gè)復(fù)雜的帶有拼寫錯(cuò)誤的關(guān)鍵字的布爾和關(guān)鍵字查詢。
內(nèi)部數(shù)據(jù)庫可以是個(gè)常規(guī)的SQL服務(wù)镀虐,處理標(biāo)準(zhǔn)化數(shù)據(jù)箱蟆,并以能完全描述數(shù)據(jù)復(fù)雜性的形式將數(shù)據(jù)分離并放入表中。不應(yīng)該在這上面跑查詢刮便, 所以并不需要需要非常重視能以最小的開銷進(jìn)行聯(lián)合查詢空猜。這非常依賴于來自于同一個(gè)初始化數(shù)據(jù)集的用以連接信息的外鍵。
它也會(huì)在每次CUD(create恨旱,update辈毯,delete)操作時(shí)觸發(fā)一個(gè)動(dòng)作。
這個(gè)觸發(fā)動(dòng)作會(huì)將信息收集到一個(gè)獨(dú)立的文檔中搜贤,比如一個(gè)嵌套的JSON對(duì)象谆沃。然后將這份文檔插入或者更新到外部數(shù)據(jù)庫中;也就是你選擇的NoSQL數(shù)據(jù)庫仪芒。對(duì)于這個(gè)目標(biāo)唁影,我個(gè)人在Elasticsearch上有很多的經(jīng)驗(yàn)。
從用戶那里來的請(qǐng)求掂名,無論多么復(fù)雜夭咬,都能形成一個(gè)針對(duì)NoSQL數(shù)據(jù)庫的查詢,而這個(gè)查詢是很快的铆隘。如果性能不夠好卓舵,那么只要改變一下文檔的結(jié)構(gòu)(或者,比如說使用了Elasticsearch膀钠,索引要進(jìn)行映射)或者重新對(duì)數(shù)據(jù)構(gòu)建索引掏湾,來達(dá)到提升性能的目的裹虫。
外部數(shù)據(jù)庫完全可以處理讀請(qǐng)求。如果你想針對(duì)一款無需向下兼容的應(yīng)用的搜索進(jìn)行修改融击,你可以并行的將數(shù)據(jù)構(gòu)建索引后放入新的數(shù)據(jù)庫中筑公,然后在結(jié)束后進(jìn)行一次性的無縫切換。
最終的結(jié)果是一個(gè)近乎實(shí)時(shí)的尊浪、結(jié)構(gòu)化的匣屡、易于更新的、查詢非衬吹樱快的捣作、并且在吞吐量增加的時(shí)候非常容易水平擴(kuò)展的NoSQL數(shù)據(jù)庫。