如何配合使用NoSQL和SQL,特別是原子性問題存在的時候?

在設計一個應用的資料庫中發現一個需要NoSQL和SQL配合的問題還請各位大神賜教!

比如需要有一個用戶表,表中存放用戶相關的信息,考慮到用戶表欄位未來可能會做很多增刪操作(比如突然增加一個「瀏覽記錄」的多值欄位),這種可能一個用戶欄位會變化且存在多值欄位的情況似乎使用NoSQL會比較合適。同理,應用中的讀書會因為也有類似特性也打算用NoSQL。

然而問題來了。。應用中需要支持用戶發起讀書會並管理要參與讀書會的用戶,因為有查詢每個用戶的所有發起的讀書會及每個讀書會的所有參與用戶的需求,如果維護每個用戶的一個讀書會表和每個讀書會的一個用戶表用NoSQL會比較麻煩(特別是在刪除的時候),因此考慮是在關係型資料庫里存用戶-讀書會的二元對。由於NoSQL本身不支持事務更不要提跨資料庫事務。。那麼在一個用戶發起讀書會時,我需要先在NoSQL里新建一個讀書會,然後同時往關係型資料庫里插入第一個用戶-讀書會的二元對,這樣兩個操作似乎並不能保證原子性。。。也許會造成一定的問題?(比如別人已經能看到讀書會了但是卻看不到有參與的第一個人)

不知道大神們覺得這個問題應該怎麼解決?希望解決的同時能充分利用好NoSQL和SQL的特性。


事實是像這樣的項目「原子性問題並不存在」,現實中的多數項目原子性是nice to have,只有少數系統中才是must have(比如金融結算)。所以單純用NoSQL沒什麼不可以,在程序調試充分的前提下,多文檔操作出現不一致的幾率極小,即使出現,做一個data fix的開銷也不大;做data fix的機制你有選擇,可以log下來然後fix,可以報錯然後在應用層回滾(你的業務邏輯並不複雜),甚至可以完全不管。

主流NoSQL一個document的大小可以過10M,對於小數據量的應用,把用戶所在的讀書組和用戶所讀的書做成內聯的數組也未嘗不可。實際的document大小可能連500k都超不過。

如果你用MongoDB,看一下這個:https://docs.mongodb.org/manual/core/write-operations-atomicity/

書,用戶,和用戶組這樣的實體欄位沒有那麼不確定,這些實體早被設計了千萬次了,即使有不確定性,增刪欄位在SQL資料庫里是完全合理合法的操作。所以單純用SQL也沒有不可行的。用兩個資料庫來解決一個不複雜的模型設計,值得這樣麻煩嗎?

你只是需要做一個權衡而已,權衡並不是什麼好處都想要,而是找到足夠好的方案。書本上會大說特說transaction/atomicity,是理解的需要;多數應用項目,原子性很少是設計中的主要考慮;用缺乏原子性(其實我們真正在討論的是transaction,資料庫或多或少都有原子性的)的資料庫也極少成為問題;用有原子性支持的資料庫也並不是總是用到這個功能,有時候甚至會主動不用,因為有開銷,還有並不是非用不可。


1.從問題描述來看,你需要Nosql執行事務功能。

2.Nosql沒有真正的事務功能(有些Nosql產品有假事務功能)。

3.可以藉助SQL來給Nosql模擬一套事務功能,但實現非常複雜、麻煩、容易出錯,而且實現後性能極低。

4.這個問題的根源在於,當初使用Nosql之前,你們根本沒認識到Nosql到底是什麼。

5.建議做法:需要事務的功能,不用Nosql,用SQL。


用postgresql,jsonb欄位的存在可以讓你同時擁有sql及nosql的好處。


nosql是用來保存沒有關係的數據的。如果你的業務邏輯決定了你的數據有關係,那你的nosql就只能用來做cache。不要糾結這個問題了,後台趕緊換成sqlserver。


瀉藥。贊成 @itlr的說法,大多數情況下,原子性是個nice to have的方案。資料庫事務是個代價高昂的東西,我對它的態度是,必要時才用。很多時候,我們樂意去犧牲一些極端情況下的一致性,換取代碼和部署的簡單高效靈活。至於極端的情況,只要做好日誌等記錄,通過自動或手動的反操作或者重試(所謂沖正),還是能達到「最終一致性」的。只要把控好一條底線——不要發生不可挽救的數據丟失,剩下的都是成本和收益的權衡


可以把讀書會的有關的數據操作用一個完整的模塊來封裝。在創建、加入、退出、解散讀書會的時候,由代碼保證事務。比如先操作一張表,成功就再操作另外一張;如果操作第二張表失敗,則回退第一張表的操作。注意,在對讀書會的數據操作時要嚴格保證必須調用該模塊。

不過不推薦這樣做。維護兩個資料庫畢竟是很麻煩的事情。可以考慮使用berkely db的secondary database技術去實現。簡單來說就是建一個索引表去保存用戶和讀書會的關係,避免編程實現的複雜度。


註定會高並的業務系統,一開始設計的時候,尤其是在數據落地或者有大量IO的地方認真分析. IO是大部分系統的瓶頸. 所以, 在IO上哪些數據是要事務一致性的,哪些要高吞吐的,哪些是低時延的,然後再決定用什麼中間件.

=============================================

然對你來說來,並沒有什麼用,你這兒不會是什麼高並發的系統,趕緊把任務實現了交作業.


用關係型資料庫存用戶id和讀書會,以事務保障原子性。然後在mongodb裡面存用戶id以及容易變化的用戶信息欄位。讀取數據的時候做關聯。

寫用戶數據的時候先寫關係型資料庫,拿到自增id再寫mongodb。你問mongodb寫失敗了怎麼辦?這個不重要。


理論點:可以處理,加事務;

實際點:一般情況下,事務的代價都會讓你有想死的心,然後你就會乖乖地容忍其非原子/不一致。


就像前面好多人說的,你的這種情況不需要原子性,因為一旦出問題,好修補且造成的危害小。

另外覺得題主的觀點似乎隱含的表達了選用nosql的一個原因是數據格式自由,我到覺得這點其實對於你描述的需求,sql也能滿足了


sql裡面可以存放text,text可以存放json,json可以存放新的欄位。不要為了nosql而nosql


從你在知乎問架構來看,你數據不像是大到到要上nosql。為了用戶表強行放瀏覽記錄欄位而上nosql肯定沒有必要,搞什麼用戶-讀書會的二元對也是不可能發揮nosql的scalability的。真要上nosql,必然要做好無ACID的準備。


我一般只用SQL。偶爾SQL為主,NoSQL做一點點東西。


推薦閱讀:

從oracle到mysql引發的技術思考,數據如何拆分到多個資料庫?
Access資料庫如何使用?
資料庫設計冗餘欄位問題?
國家能不能建立一個新生兒DNA比對資料庫來預防小孩被拐賣?
互聯網產品採用哪些方案可以實現多賬號綁定、合併和解綁?

TAG:資料庫 | SQL | NoSQL | 資料庫設計 | 關係資料庫 |