由亞馬遜內部禁止使用SQL資料庫引出的想法 - nelhage

發表於2021-04-08

和我一起工作的人往往會意識到我對資料庫特別是對SQL資料庫有意見。上週,我寫了一篇Postgres除錯故事,並在推特上釋出了AWS禁止內部使用SQL資料庫的政策,並在Twitter上進行了討論和辯論。本文是為了將其中的更多內容寫到一個我可以引用的地方。

我相信這裡的大多數評論都適用於大多數SQL引擎,但是由於我熟悉這些引擎,因此本文的重點將主要放在MySQL和Postgres以及偶爾的SQLite上。它們之間還涵蓋了絕大多數開源SQL引擎的用法。

這些意見來自多年使用和/或執行SQL和其他資料庫(主要作為Web應用程式或Web API的後端)的觀點。我的經驗主要是在這類應用程式中,這些應用程式往往具有相對可預測的資料訪問模式,並且關心低延遲,高吞吐量和某種程度的高可用性。

 

SQL資料庫具有令人難以置信的儲存引擎

SQL資料庫中的儲存引擎是負責實際管理磁碟上的資料,將其持久化到磁碟並從中讀回的層。它們是資料庫中所有其他功能的基礎。在(非分散式)SQL資料庫中,它們在資料庫的事務功能中也起著主導作用,管理原子提交背後的大多數複雜性,並介導資料庫的許多一致性和隔離性。當我們談到“ ACID”時,這些功能在很大程度上是儲存引擎的屬性,或者至少植根於儲存引擎的屬性。

開源SQL資料庫絕對具有世界上最好的儲存引擎。它們通過適當的調整和維護,提供了出色的吞吐量和底層硬體的高利用率,同時提供了強大的永續性保證和事務語義。它們有不同的優點和缺點,但是,如果您要持久地將一些低階記錄儲存在磁碟上,那麼用通用的方法很難比MySQL的InnoDB,PostgreSQL或SQLite的儲存層做得更好。

實際上,這些儲存引擎是如此之好,以至於它們是單獨使用這些資料庫的原因。即使使用瑣碎的(id int primary key, data blob)鍵值模式,使用SQL資料庫也是有意義的,只是為了訪問底層儲存層的效能和永續性。

 

不喜歡SQL幾個方面

那些令人難以置信的儲存引擎(我們可以使用的一些最優秀的系統工程)都隱藏在我認為非常令人沮喪的介面後面。讓我們看看我對SQL不滿意的地方。

  • 字串連線是錯誤的

即使您確定始終對實際資料使用查詢引數(也應該如此),但針對SQL資料庫編寫程式碼幾乎總是最終會通過在某些時候將字串貼上在一起而構造查詢字串,充其量,這是笨拙且麻煩的,更糟的是,它容易出錯。

對於應用程式的程式設計使用,我寧願使用一個從頭到尾結構化資料的API,例如GRPC架構甚至MongoDB的BSON。以程式設計方式使用以消耗,生產或分析,並消除了所有潛在的錯誤,這要容易得多。

  • 不喜歡查詢Planer

我不能否認查詢計劃者Planer非常有用,並且對於宣告式查詢執行的夢想有些不可思議的地方,您只需寫下一個謂詞,然後引擎“神奇地”使之高效。

但是,對於應用程式開發而言,絕大多數時候您都知道資料訪問模式是什麼,並且已經圍繞它們設計了索引,並具有可預測性。對於具有一致的資料訪問模式和高吞吐量的線上應用程式,效能是資料庫介面的一部分;如果資料庫繼續提供查詢服務,但延遲時間大大延長。

查詢計劃程式是可預測性的對立面。在大多數情況下,它會選擇正確的,但是很難知道什麼時候不會正確,或者如果不正確會產生什麼樣的影響。查詢計劃人員根據資料分佈的估計來更改行為,因此即使EXPLAIN在CI時間執行也不足以提供保證。SQL引擎真的很難保證查詢執行中的可預測效能。

尤其是Postgres頑固地拒絕執行強制選擇索引的任何雜注,這令我非常惱火。這不是他們的計劃者是否足夠聰明的問題(儘管我遇到過犯嚴重錯誤的情況!),而是關於開發和資料管理的思維方式的問題。在某些時候,透明度,明確性和可預測性是非常重要的價值。

非常相似的查詢將執行不同的查詢,具體取決於存在的索引和計劃者選擇的索引,這很難預測。從

隨著查詢變得越來越複雜,查詢計劃程式問題在許多方面都變得越來越嚴重。

  • 不喜歡型別系統

SQL型別系統來自另一個時代。我寧願選擇像protobuf的型別系統那樣的東西,該系統幾乎完全專注於描述磁碟上的表示形式,並允許使用者定義將語義分層的結構。總的來說,我認為在“儲存型別”和“語義型別”之間更強的分離可能是一個富有成效的步驟。

而且,有這麼多粗糙的邊緣和怪異的角落:為什麼Postgres有bytea其他資料庫都有blob?為什麼bigint在大多數引擎中都是64位整數,即使該詞在大多數程式語言中表示“任意精度整數”也是如此?

這些並不是很大的問題,但是就造成精神開銷和引擎與應用程式之間的阻抗不匹配而言,它們不是強制性的錯誤。

 

SQL是一種不錯的ad-hoc查詢和報告語言

鑑於對SQL的所有負面評價,SQL是一種相當不錯的即席查詢語言或探索性工具。如果我有一個很大的資料集要進行互動瀏覽,我的第一步通常是將其匯入到SQLite中以進行互動操作,因為以一種簡潔明瞭的方式來詢問各種不同的問題非常容易。

對於互動使用的SQL,有很多技巧可以選擇,但是在我看來,這在網路上確實是一種語言。

這種優勢在某種程度上也可以延續探索性發展;如果您要構建一個快速迭代的早期應用程式,則可以使用SQL並使用查詢計劃器來編寫當前所需的任何查詢,然後在以後使它們變得高效-甚至以後,對於該功能-確實有價值。

 

遷移可能是我使用SQL資料庫最大的麻煩

SQL資料庫具有命令性的架構定義(CREATE TABLE …然後是ALTER TABLE …或CREATE INDEX…)。在我看來,絕大多數模式定義都應該是宣告性的:您只需告訴資料庫該模式應該是什麼,它會對當前模式進行內省,然後將其演化為新的模式。如果無法自動執行此操作,則會引發錯誤,您需要在架構中新增其他編譯指示或後設資料以告知執行操作。

大多數ORM都以某種方式採用了這種方法,這就是為什麼它對我感覺如此正確的部分原因。令我感到沮喪的是,SQL資料庫本身無法以這種方式工作,而我們所有人都一次又一次地重新發明輪子,或者僅僅依靠重量級的ORM和應用程式框架來使我們的資料庫可用。SQL資料庫已經非常複雜,並且為它們的宣告性查詢語言感到驕傲。

許多ORM和框架都很好地解決了這個問題,但是當從頭開始一個新專案時,這確實是煩人的設計選擇和樣板的真正根源。我認為這裡的啟動成本以及迭代的痛苦–編寫和執行遷移操作只是為了向物件新增新欄位,感覺非常沉重!

我認為這裡的一個主要因素是,SQL引擎就像是一個時代的遺物,該時代做了更多的“前期大設計”。如果您在實施系統之前進行了大部分設計,則可以進行相當繁重的遷移過程。但是,現在我們強調緊密的迭代和敏捷演進,而我不得不編寫並執行遷移只是為了有效地嚮應用程式中新增新欄位,這讓我感到非常惱火。

 

建議使用哪種技術進行資料儲存?

細節在於魔鬼,但對我而言,預設情況下,儘管存在所有這些煩惱,我還是從MySQL開始。

這個答案常常使人們感到驚訝,因為MySQL的起步階段很糟糕。然而,如今,帶有InnoDB的MySQL2個作為一種儲存引擎,它是我們擁有經過最嚴格測試和精心設計的軟體之一。它已經由某些大型科技公司(包括Facebook和Google)以全球規模執行(並且在某些情況下仍處於執行狀態)。反過來,他們投入了大量的工程工作來增強它的效能以及大規模的穩定性和可操作性。如今,MySQL甚至具有通過Vites基本上可用的現成的群集功能。

顯然,MySQL遭受以上所有抱怨。仍然必須謹慎使用它,如果我要針對它開發應用程式,我將嘗試儘可能地使用盡可能少的功能集。但歸根結底,它的成熟性和靈活性將使我勝過大多數更新或趨勢更強的NoSQL引擎。

至於Postgres,我對它以及它的工程和功能都非常敬重,但是對我來說,它在操作上太可怕了。在我的經驗,這是很多比MySQL更糟糕的運營footguns和效能的懸崖,在使用它稍有不妥就可以完全破壞的效能或可用性。

另外,根據我的經驗,由於MySQL的部署範圍更廣,因此更容易找到和僱用具有部署和操作經驗的工程師。Postgres是一個不錯的選擇,特別是如果您已經在團隊中使用過Postgres ,但是我個人已經被燒死了很多次。

更多點選標題原文。

 

相關文章