來源:北大青鳥總部 2023年04月04日 15:42
傳統(tǒng)數(shù)據(jù)庫如Mysql、Oracle的出現(xiàn)解決了早期互聯(lián)網(wǎng)對于數(shù)據(jù)存儲、數(shù)據(jù)一致性的問題,但隨著互聯(lián)網(wǎng)、物聯(lián)網(wǎng)的快速發(fā)展而導(dǎo)致對數(shù)據(jù)存儲的要求不只是數(shù)據(jù)一致性,還有了更多特性需求。
傳統(tǒng)數(shù)據(jù)庫有幾個缺點:在大數(shù)據(jù)場景下讀取IO較高、無法存儲靈活的數(shù)據(jù)結(jié)構(gòu)、表結(jié)構(gòu)擴展不方便、全文搜索功能較弱(使用索引效率低)、不擅長出復(fù)雜關(guān)系型數(shù)據(jù)庫,因此非關(guān)系型數(shù)據(jù)庫NoSQL是極好的解決方案。
作為關(guān)系型數(shù)據(jù)庫的補充,再根據(jù)互聯(lián)網(wǎng)時代的需求不同,NoSQL可以分為:
支持高性能并發(fā)讀寫的Key-Value數(shù)據(jù)庫,如Redis;
支持海量數(shù)據(jù)訪問的文檔數(shù)據(jù)庫,如MongoDB、CouchDB;
支持大數(shù)據(jù)存儲和分析的列式數(shù)據(jù)庫,如HBase;
支持全文搜索的搜索引擎數(shù)據(jù)庫,如ElasticSearch。
Key-Value數(shù)據(jù)庫
所謂KV數(shù)據(jù)庫就是按照鍵值對進行存儲的數(shù)據(jù)庫,key是數(shù)據(jù)的標(biāo)識,value是數(shù)據(jù)的值。Redis是典型的KV數(shù)據(jù)庫,可以存儲string、hash、list、set等數(shù)據(jù)結(jié)構(gòu)。
我們以微博清除歷史粉絲為例,對于redis來說,只要使用RPOPkey從隊列的右邊出隊一個元素就可以了。是不是很簡單?
但如果是關(guān)系數(shù)據(jù)庫就比較復(fù)雜了,因為關(guān)系型數(shù)據(jù)庫是行式存儲,所以在建表時每條數(shù)據(jù)除了有數(shù)字編號之外,還有位置編號,用于判斷數(shù)據(jù)是否第一條,其次通過sql語句找到了第一條數(shù)據(jù)之后,再次執(zhí)行sql刪除語句,最后更新從第二條開始的所有數(shù)據(jù)的位置編號。可以看到關(guān)系型數(shù)據(jù)庫需要進行多次SQL操作,實現(xiàn)非常麻煩,效率低,性能低。
Redis數(shù)據(jù)庫的主要缺點是不支持完整的ACID事務(wù),但其實大部分業(yè)務(wù)也不需要嚴(yán)格遵守ACID原則,比如剛剛的微博粉絲案例,少一個或多一個粉絲對于我們并沒有什么影響。
文檔數(shù)據(jù)庫
所謂文檔數(shù)據(jù)庫就是可以存儲和讀取任意的數(shù)據(jù),在使用之前不需要定義字段,讀取某個不存在的字段也不會報錯,目前大部分文檔數(shù)據(jù)庫存儲的數(shù)據(jù)格式是JSON,可以支持比較復(fù)雜的數(shù)據(jù)結(jié)構(gòu),MongoDB是典型的文檔數(shù)據(jù)庫。比如一個商品信息管理系統(tǒng),商品的信息有商品ID、生產(chǎn)日期、品牌、貨號、口味、包裝方式、凈含量、產(chǎn)地、生產(chǎn)許可證編號、廠名、配料表、存儲方法、保質(zhì)期、食品添加劑。其中口味是一個列表(因為口味可以有多個),產(chǎn)地是一個結(jié)構(gòu)(包含省市區(qū)具體地址),保質(zhì)期包含包裝方式、生產(chǎn)日期、存儲時長等。如果使用文檔數(shù)據(jù)庫,一個JSON就可以完全描述。
如果使用關(guān)系型數(shù)據(jù)庫,則需要設(shè)計多張表并且關(guān)聯(lián)起來,包含基本信息(有商品ID、價格、品牌三列)、地址(有省份、市區(qū)、鄉(xiāng)鎮(zhèn)、小區(qū)、門牌號四列)、配料表(有雞蛋、面粉、食鹽、添加劑等多列),表創(chuàng)建后再使用Join將所有的內(nèi)容關(guān)聯(lián)起來,最終形成一個商品信息提供給到用戶。
文檔數(shù)據(jù)庫有兩個缺點。
缺點之一是不支持事務(wù)操作,比如使用MongoDB來存儲商品庫存,用戶付款、減庫存屬于一個事務(wù)操作,用關(guān)系型數(shù)據(jù)庫就很簡單,如果使用MongoDB來實現(xiàn),就可能出現(xiàn)庫存減了但是用戶沒有付款的情況。
缺點之二是不支持join操作,比如我們想查詢購買了陳克明面條中的女性用戶,使用關(guān)系型數(shù)據(jù)庫,將用戶信息表和訂單表通過用戶ID來join操作就可以了,如果使用MongoDB,則需要查詢訂單表中買了陳克明面條的用戶,再查詢用戶中的女性用戶。
列式數(shù)據(jù)庫
所謂列式數(shù)據(jù)庫就是按照列來存儲數(shù)據(jù)的數(shù)據(jù)庫,傳統(tǒng)的關(guān)系型數(shù)據(jù)庫是按行來存儲在磁盤,即行式數(shù)據(jù)庫,典型的列式數(shù)據(jù)庫是HBase。怎么理解行式和列式存儲呢?
以某個用戶信息登記表來說,按行存儲是二維表格中的每一行占據(jù)一塊連續(xù)的存儲空間,按列存儲則是每一列占據(jù)一塊連續(xù)的存儲空間。所以列式存儲數(shù)據(jù)庫非常適合大數(shù)據(jù)分析場景。
比如我們想分析某個區(qū)域的平均身高和體重,在mysql數(shù)據(jù)庫中需要獲取到每行的身高、體重數(shù)據(jù),再來求平均,如果有10000個人,就需要請求磁盤空間10000次;在hbase數(shù)據(jù)庫中我們只需要請求兩次,獲取身高和體重這一列的數(shù)據(jù)求平均即可。
中期的時候是敏捷開發(fā)模型。因為互聯(lián)網(wǎng)上涌入的網(wǎng)民開始增多,大家的關(guān)注點開始變成好用、好玩,而此時一些有遠見的人開始注意到互聯(lián)網(wǎng)紅利,投身于互聯(lián)網(wǎng),此時的開發(fā)模式演變成了敏捷開發(fā)模型。
敏捷開發(fā)模型面對的是頻繁的需求變化,要求快速開發(fā)。比較流行的實際案例則是Scrum、XP極限編程。在新迭代(一般2-6周)開始前,產(chǎn)品經(jīng)理將需求拆分成具體的開發(fā)任務(wù),研發(fā)人員進行任務(wù)認(rèn)領(lǐng),每日站會進行任務(wù)的review,直到開發(fā)完成,發(fā)布新的可用版本。
列式數(shù)據(jù)庫的缺點就是不適合小量數(shù)據(jù)、不適合隨機的更新數(shù)據(jù)、不適合有刪除和更新的實時操作、不適合ACID事務(wù),因為列式存儲中要隨機的去更新數(shù)據(jù)或刪除某條數(shù)據(jù),比較耗費磁盤IO,影響整體的性能。
搜索引擎數(shù)據(jù)庫
所謂搜索引擎數(shù)據(jù)庫就是支持在數(shù)據(jù)庫內(nèi)通過關(guān)鍵字全文檢索,傳統(tǒng)的關(guān)系型數(shù)據(jù)庫是通過索引,比如like、where等語句來達到快速查詢,在全文檢索的情況下,需要整個表掃描,效率非常低。ElasticSearch是典型的全文搜索引擎數(shù)據(jù)庫,采用倒排索引的模式,建立從單詞到文檔的索引關(guān)系。比如現(xiàn)在我們有這樣的一個文檔集合,按單詞將文檔內(nèi)容進行拆分,如文檔1-谷歌地圖之父跳槽Facebook,可拆分成單詞谷歌(單詞ID為1)、地圖(單詞ID為2)、之父(單詞ID為3)、跳槽(單詞ID為4)、Facebook(單詞ID為5),其余的依次拆分可得到如下的倒排索引表….
通過關(guān)鍵字就可以檢索文章了,我們在數(shù)據(jù)庫搜索谷歌時,所有的結(jié)果都會返回,搜索創(chuàng)始人時則只返回“谷歌地圖創(chuàng)始人拉斯離開谷歌加盟Facebook”。
SQL與NoSQL在是隨著互聯(lián)網(wǎng)的發(fā)展衍生的不同產(chǎn)物,在某一類業(yè)務(wù)的處理上都有自己的強項,在本文中我們介紹了四種類型的非關(guān)系型數(shù)據(jù)庫,你清楚了NoSQL哪些地方強了嘛?而在業(yè)務(wù)中,我們將SQL與NoSQL結(jié)合,取長補短,賦能業(yè)務(wù)即可~