我的第一個以 MongoDB 作為主數據庫開發的網站是 codecampo.com(2011 年),第二個是 writings.io(2013 年)。Campo 在第 3 版的時候重寫(2014 年)遷移到 PostgreSQL,而 writings.io 已經關閉了,現在正在做的創業項目 selfstore.io 也是使用 PostgreSQ
我的第一個以 MongoDB 作為主數據庫開發的網站是 codecampo.com(2011 年),第二個是 writings.io(2013 年)。Campo 在第 3 版的時候重寫(2014 年)遷移到 PostgreSQL,而 writings.io 已經關閉了,現在正在做的創業項目 selfstore.io 也是使用 PostgreSQL。PostgreSQL 已經成為我的默認數據庫,鑒于我曾經做過一段時間 MongoDB 布道者,所以我想有必要總結一下。
我開發維護的都是流量很小的網站,所以不用期待我分享千萬級數據管理的經驗(我以前正式工作中倒是接觸一個千萬級使用 MySQL 的網站,但優化工作不是我做的)。我也不會犯一些低級錯誤,例如項目開發到一半才困惑“MongoDB 沒有 JOIN 查詢怎么辦?”,選型時已經知道將要面臨怎樣思維轉換。
我不希望這篇文章被當作是“XX 已死,YY 永生”一類的噱頭文章,這類文章大多帶有偏見,并且對評論對象淺嘗輒止。不同的工具有不同的應用場合,不能一概而論。
我從 MySQL 轉向 MongoDB,以及從 MongoDB 轉向 PostgreSQL 的最大原因都是:有趣。Web 開發一個優點就是你不用限定在某個平臺某類技術上,最終用戶看到的都是 HTML 頁面。
下面是一些我選擇數據庫的經驗。
無模式是個雙面刃。好的方面,它可以減少表的空余字段,減少拆表的必要,例如用戶集合可以一條記錄帶有 admin: true
屬性,其他不帶有這個屬性,而在關系數據庫中這類帶來大量空余字段的屬性最好拆表。PostgreSQL 打開 HStore 擴展后也可以實現這樣的結構。如果覺得 admin: true
的例子太簡單,可以考慮下怎么儲存 gemspec 的內容并讓它可索引。
無模式另一個好處是讓代碼邏輯管理起來更清晰,可以把屬性定義和模型邏輯放在一起:
class Artist
include Mongoid::Document
field :name, type: String
end
類似 DataMapper 的庫雖然也能實現這樣的語法,但始終需要維護一個遷移腳本,需要重復自己。用 Mongoid 的時候我一直覺得打開 Model 文件先看到屬性定義很舒服。
無模式的最大壞處就是無法真正掌握數據庫中有什么內容,實際上并不是經常需要儲存無模式數據,多數是模式化數據。所以即使不需要管理模式遷移,還是要管理數據遷移,每次更改屬性相關邏輯時要寫數據遷移腳本。這里無模式是好是壞取決于應用場景。
MongoDB 支持的數據類型多于 MySQL,其中最主要是 Array,Hash 類型。PostgreSQL 原生或通過擴展可以支持 Array 和 Hash,但是配套的操作不夠 MongoDB 簡便。
例如 MongoDB 對 Array 有一個 $addToSet
方法,只有數組不存在某元素時進行插入:
update( $addToSet: { upvotes_ids: 1 } )
而 PostgreSQL 要進行同樣操作需要組合一些語句:
SET upvotes_ids = array_append(upvotes_ids ,1) WHERE NOT (upvotes_ids @>array[1])
MongoDB 的語句更簡潔,也不排除 PostgreSQL 以后也會添加同樣的方法。
也許需不需要數據庫事務成了是否選擇 MongoDB 的決定性因素,MongoDB 不支持數據庫事務。
有很多應用對數據一致性其實要求不高,例如很多社交應用,大多數應用邏輯只是簡單存取(發一段文字,上傳一張照片),極少的不一致是不影響應用的。而一些嚴肅應用,例如交易系統,就很需要數據庫事務的支持了,否則就需要在應用層自己實現一個粗糙的、充滿 Bug 的事務支持。如果有興趣自己實現事務操作,可以看 MongoDB 的文章 Perform Two Phase Commits。
如果有跨系統的事務操作,就不能完全依賴數據庫事務,還要有應用層的重試或回滾操作(例如遠程調用支付接口)。數據庫層面支持事務的話,起碼讓維護系統內部數據一致性更輕松。
MongoDB 的原生查詢語法是 JavaScript,JavaScript 程序員可能對此欣喜若狂。我最初感覺也是很新鮮,但久了就覺得很煩躁。JavaScript 太多的括號和花括號,在組合多個查詢條件的時候作括號匹配很費神。SQL 是一個查詢 DSL,雖然看起來有點古老,但是在查詢這個特定領域上做得很好。
如果應用使用 ORM,可能很多時候不需要寫原生查詢語句。除了 PHP 社區外,其他社區也不推薦寫原生查詢。不過少數情況下,復雜查詢還是原生語句更高效,而且數據庫終端也是調試查詢錯誤的最終手段,所以查詢語法至少不能讓人難受。
MongoDB 的開發者假設你是一個資深系統管理員,并且把 MongoDB 部署在安全的內部網絡當中,所以他們官方安裝包內含的配置沒有設置任何安全驗證,接收任何來源的訪問,結果就是一些初級系統管理員(例如我)把 MongoDB 直接暴露到了公網,造成數據泄漏。
這不僅是 MongoDB 的問題,Redis、Elasticsearch 也是這樣,姑且把這認為是一種設計“哲學”。Ubuntu 的軟件源管理者不認同這個“哲學”,從軟件源安裝的 MongoDB 的默認只接受本地連接,這保護了一些初級系統管理員,但如果追新使用數據庫開發方的安裝包就會中招。順便一提,PostgreSQL 默認配置只接受本地連接。
無論用什么數據庫都好,使用前一定要完整讀一遍文檔,特別是設置和安全相關的章節,同時設置系統防火墻。
MongoDB 的官方驅動更新沒有問題,不過一般不會直接使用驅動寫程序(寫過,很繁瑣),而是使用 ODM(對象-文檔映射)工具,在 Ruby 中就是 Mongoid。
Mongoid 已經做得很好,提供了類似 ActiveRecord 的 API,并且很好的利用了 MongoDB 的特性,但在關注度和社區規模上還不及 ActiveRecord。ActiveRecord 作為 Rails 的默認組件,每次都是跟隨 Rails 的更新同時更新的,Mongoid 則要滯后一段時間。所以如果你希望緊跟 Rails 的更新,那么最好使用 ActiveRecord 和關系數據庫。
今年開始,我的精力投入到一個交易網站的開發,所以一開始就打算遷移到關系數據庫。至于為什么用 PostgreSQL 而不是 MySQL/MariaDB,有幾個理由:
includes
方法,基本上只做主鍵查詢,所以我之前那么容易接受 MongoDB。基于以上理由,我選擇了 PostgreSQL,目前為止工作得很好。
這幾年間我接觸了 3 個數據庫(不包括 Redis 的話),SQL-NoSQL-SQL 的切換讓我對數據庫有了更深刻的理解,也認識到還有很多類型數據庫我沒試過,關系數據庫不是唯一選擇。我的幾個項目都是只是玩具規模,沒什么說服力,但以免被誤解,還是提幾條建議:
最終,選擇要取決于你的應用場景。
原文地址:為什么我從 MongoDB 遷移到 PostgreSQL, 感謝原作者分享。
聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com