SQL vs NoSQL:為滿足您的業(yè)務(wù)需求選擇正確的數(shù)據(jù)庫模型

關(guān)于基本SQL的快速回顧
SQL(Structured Query Language)數(shù)據(jù)庫,也稱為關(guān)系數(shù)據(jù)庫,是一種基于關(guān)系模型的數(shù)據(jù)庫管理系統(tǒng)(DBMS)。它以結(jié)構(gòu)化的方式組織和存儲數(shù)據(jù),使用帶有行和列的表來表示實體及其關(guān)系。
SQL數(shù)據(jù)庫使用一種稱為SQL的結(jié)構(gòu)化查詢語言與數(shù)據(jù)庫進(jìn)行交互。SQL提供了一組命令和語法,用于定義、操作和檢索數(shù)據(jù)庫中的數(shù)據(jù)。使用SQL,您可以創(chuàng)建表,使用主鍵和外鍵定義表之間的關(guān)系,插入和更新數(shù)據(jù),并查詢數(shù)據(jù)庫以檢索特定信息。

一些流行的SQL數(shù)據(jù)庫系統(tǒng)包括:
- MySQL → 一種廣泛用于Web應(yīng)用程序的開源關(guān)系數(shù)據(jù)庫管理系統(tǒng)。
 - PostgreSQL → 一種以其可擴(kuò)展性和高級功能而聞名的開源面向?qū)ο箨P(guān)系數(shù)據(jù)庫。
 - Microsoft SQL Server → 一種由Microsoft開發(fā)的商用RDBMS,通常用于基于Windows的環(huán)境。
 
關(guān)于基本NoSQL的快速回顧
NoSQL數(shù)據(jù)庫,也稱為非關(guān)系數(shù)據(jù)庫,是一種與傳統(tǒng)SQL(Structured Query Language)數(shù)據(jù)庫不同的數(shù)據(jù)庫管理系統(tǒng)類型。

流行的NoSQL數(shù)據(jù)庫包括:
- MongoDB → 一種面向文檔的NoSQL數(shù)據(jù)庫,提供可伸縮性、靈活性和豐富的查詢功能。
 - Cassandra → 一種高度可擴(kuò)展和分布式的NoSQL數(shù)據(jù)庫,設(shè)計用于處理跨多個通用服務(wù)器的大量數(shù)據(jù)。
 - Redis → 一種支持鍵值數(shù)據(jù)存儲的內(nèi)存型NoSQL數(shù)據(jù)庫,提供高速數(shù)據(jù)訪問。
 - Amazon DynamoDB → 由Amazon Web Services(AWS)提供的全面托管的NoSQL數(shù)據(jù)庫服務(wù),提供可伸縮性、高可用性和低延遲性能。
 
NoSQL數(shù)據(jù)庫通常用于需要處理大量快速變化的數(shù)據(jù)的情況,例如社交媒體平臺、物聯(lián)網(wǎng)應(yīng)用程序等。
通過本文,我們將了解數(shù)據(jù)庫如何擴(kuò)展和不擴(kuò)展。我們將研究傳統(tǒng)SQL數(shù)據(jù)庫存在的一些問題以及NoSQL數(shù)據(jù)庫的引入如何解決這些問題。我們將涵蓋適合通過SQL數(shù)據(jù)庫解決的情況以及更適合NoSQL數(shù)據(jù)庫的情況。
關(guān)于關(guān)系數(shù)據(jù)庫的問題
關(guān)系數(shù)據(jù)庫適用于各種用例,并且通常是許多開發(fā)人員在開發(fā)應(yīng)用程序時的默認(rèn)選擇。此外,關(guān)系數(shù)據(jù)庫具有SQL,這使得可以在單個數(shù)據(jù)庫中處理新的訪問模式以及OLTP和OLAP模式成為可能。
- OLTP → 它代表在線事務(wù)處理。它指的是支持實時事務(wù)導(dǎo)向工作負(fù)載的一類計算機(jī)系統(tǒng)和應(yīng)用程序。OLTP系統(tǒng)旨在通過處理大量的短時且快速的數(shù)據(jù)庫事務(wù)來促進(jìn)和管理組織的日常運(yùn)營活動。
 - OLAP → 它代表在線分析處理。它指的是支持復(fù)雜數(shù)據(jù)分析、報告和決策任務(wù)的計算機(jī)系統(tǒng)和應(yīng)用程序的一類。OLAP系統(tǒng)旨在處理大量數(shù)據(jù)并提供用于交互式和臨時分析的多維視圖。
 
OLTP vs OLAP[1] ← 這是一篇很好的文章,清晰地解釋了OLAP和OLTP的含義及其區(qū)別,并提供了兩者之間的簡潔比較。如果您想進(jìn)一步了解,請查看。
然而,為了提供這些功能,關(guān)系數(shù)據(jù)庫通常遇到以下問題:
- 查詢性能的不可預(yù)測性
 - 連接的問題
 - 難以水平擴(kuò)展的DB實例
 
查詢性能的不可預(yù)測性
在測試和應(yīng)用程序生命周期的早期開發(fā)和發(fā)布階段,您的應(yīng)用程序通常具有快速響應(yīng)的查詢。

**帶有5GB數(shù)據(jù)的RDBMS數(shù)據(jù)存儲的表示**
然而,隨著表的大小增長,這些操作會變得越來越慢。性能還受到同時運(yùn)行的其他查詢的影響。同時,如果公司的數(shù)據(jù)分析師在生產(chǎn)中對相同表進(jìn)行分析操作,那么情況會變得更加復(fù)雜。

帶有500GB數(shù)據(jù)的RDBMS數(shù)據(jù)存儲的表示
這導(dǎo)致了第二個問題。
與所有著名的連接存在問題
SQL中的連接可以由于多種原因而損害速度:
- 大結(jié)果集 → 在執(zhí)行連接操作時,如果連接的表之間有許多匹配行,結(jié)果集可能會顯著增長。這可能導(dǎo)致更大的中間結(jié)果集需要處理、傳輸和存儲,從而增加了內(nèi)存消耗和較長的查詢執(zhí)行時間。
 - 缺乏索引使用 → 有效的連接操作通常依賴于連接列上適當(dāng)索引的使用。如果缺少或未正確定義必要的索引以及外鍵,數(shù)據(jù)庫可能需要執(zhí)行完整的表掃描或大量的磁盤I/O操作來定位匹配的行,從而導(dǎo)致性能較慢。
 

- 復(fù)雜的查詢計劃 → 數(shù)據(jù)庫優(yōu)化器需要確定執(zhí)行連接查詢的最有效方法。在某些情況下,查詢優(yōu)化器可能需要考慮多個可能的連接路徑、表訪問方法和連接算法。這個過程可能變得復(fù)雜且耗時,特別是對于具有多個連接的查詢,可能導(dǎo)致次優(yōu)查詢計劃和較慢的執(zhí)行。
 - 選擇性不足 → 包括非選擇性謂詞(匹配大部分?jǐn)?shù)據(jù)的條件)的連接條件可能阻礙性能。非選擇性連接條件可能導(dǎo)致更大的中間結(jié)果集和較慢的查詢執(zhí)行,因為數(shù)據(jù)庫需要處理大量數(shù)據(jù)以檢索所需的結(jié)果。
 
為了解決這些問題,您可能希望擴(kuò)展數(shù)據(jù)庫,這將導(dǎo)致下一個問題。
DB實例的水平擴(kuò)展難題
擴(kuò)展數(shù)據(jù)庫有兩種方法:
- 垂直擴(kuò)展 → 通過增加現(xiàn)有數(shù)據(jù)庫機(jī)器的CPU或RAM
 - 水平擴(kuò)展 → 通過向數(shù)據(jù)庫集群添加其他機(jī)器,每臺機(jī)器處理總數(shù)據(jù)的一個子集。
 
但是,您最終會達(dá)到垂直擴(kuò)展的極限。在這一點上,您可能希望考慮水平擴(kuò)展。但是,這會引入一套自己的挑戰(zhàn)。
- 數(shù)據(jù)分發(fā)和分片 → 在水平擴(kuò)展時,跨多個節(jié)點分發(fā)數(shù)據(jù)至關(guān)重要。在SQL數(shù)據(jù)庫中,數(shù)據(jù)通常以具有關(guān)系和依賴關(guān)系的表結(jié)構(gòu)化。拆分和分發(fā)這樣相互關(guān)聯(lián)的數(shù)據(jù)可能會很復(fù)雜,因為維護(hù)引用完整性并確保節(jié)點之間的一致數(shù)據(jù)變得具有挑戰(zhàn)性。通常會使用分片技術(shù)來將數(shù)據(jù)分區(qū)到節(jié)點上,但需要仔細(xì)規(guī)劃,可能會引入額外的復(fù)雜性。
 - 查詢協(xié)調(diào)和連接 → SQL數(shù)據(jù)庫支持復(fù)雜的JOIN操作,以從多個表中檢索數(shù)據(jù)。當(dāng)數(shù)據(jù)分布在節(jié)點之間時,執(zhí)行JOIN操作變得更加具有挑戰(zhàn)性。連接可能需要節(jié)點之間的協(xié)調(diào)、網(wǎng)絡(luò)數(shù)據(jù)傳輸和增加的網(wǎng)絡(luò)延遲,可能影響性能和可伸縮性。
 - 索引和查詢優(yōu)化 → SQL數(shù)據(jù)庫在高效的數(shù)據(jù)檢索方面嚴(yán)重依賴于索引。隨著水平擴(kuò)展,索引變得更加復(fù)雜,因為需要在節(jié)點之間分布和維護(hù)索引。由于數(shù)據(jù)的分布性質(zhì),查詢優(yōu)化技術(shù)也變得更加具有挑戰(zhàn)性,可能影響查詢性能。
 
水平擴(kuò)展在您可以分區(qū)單個請求可以由單個機(jī)器/節(jié)點處理的方式時效果最佳。
通過NoSQL數(shù)據(jù)庫解決方案
NoSQL數(shù)據(jù)庫嘗試解決關(guān)系數(shù)據(jù)庫提出的這些主要問題。
- 與所有著名的連接存在問題
 - 查詢性能的不可預(yù)測性
 - DB實例的水平擴(kuò)展難題
 
解決連接
讓我們迅速了解NoSQL在這里試圖解決什么。
SQL依賴于規(guī)范化來進(jìn)行數(shù)據(jù)建模。
規(guī)范化是數(shù)據(jù)庫設(shè)計中的一個過程,通過它來組織和結(jié)構(gòu)化數(shù)據(jù),以最小化冗余,提高數(shù)據(jù)完整
性,并優(yōu)化數(shù)據(jù)庫效率。它涉及將數(shù)據(jù)分解為較小、更可管理的實體(表),并在它們之間建立關(guān)系。
它旨在通過只在一個地方存儲每個數(shù)據(jù)片段來消除冗余。這以以下方式使我們受益:
- 靈活的查詢 → 連接允許您通過單個操作從不同表中重新組裝所需的數(shù)據(jù)。有了連接的靈活性和SQL的其他語法糖,您不需要提前考慮如何訪問數(shù)據(jù)。您根據(jù)規(guī)范化的原則來建模實體,然后編寫查詢以處理您的需求。
 - 增強(qiáng)數(shù)據(jù)完整性 → 規(guī)范化通過定義約束和表之間的關(guān)系來幫助實施數(shù)據(jù)完整性規(guī)則。主鍵和外鍵用于建立關(guān)系和強(qiáng)制引用完整性,防止數(shù)據(jù)不一致并確保數(shù)據(jù)完整性。
 - 提高存儲效率 → 冗余數(shù)據(jù),即相同信息存儲在多個地方,可能導(dǎo)致不一致和浪費(fèi)存儲空間。只在一個地方存儲每個數(shù)據(jù)片段可以降低數(shù)據(jù)不一致的機(jī)會,并提高數(shù)據(jù)準(zhǔn)確性。
 
然而,所有這些都需要付出代價。CPU和內(nèi)存的代價通常很高。
NoSQL采用了解決所有這些問題的方法。
- 解決靈活的查詢NoSQL數(shù)據(jù)庫通過要求您事先制定所有主要數(shù)據(jù)訪問模式并設(shè)計數(shù)據(jù)庫以處理這些問題來避免您在數(shù)據(jù)訪問時靈活性的需求。您不需要在讀取時匯總數(shù)據(jù),而是通過以讀取方式布置數(shù)據(jù)的方式存儲數(shù)據(jù)的預(yù)連接版本。
 - 解決數(shù)據(jù)完整性NoSQL數(shù)據(jù)庫將數(shù)據(jù)完整性的責(zé)任推到了應(yīng)用程序中。您需要將數(shù)據(jù)去規(guī)范化并復(fù)制到數(shù)據(jù)庫中。在更改時,可能需要更新包含相同數(shù)據(jù)的多個記錄。
 - **解決存儲效率**NoSQL數(shù)據(jù)庫的存儲效率不如其關(guān)系對手高。但是,當(dāng)設(shè)計RDBMS時,存儲費(fèi)用相對于計算來說非常昂貴。與當(dāng)前情況相比,存儲價格已經(jīng)大幅下降,計算則成為首選。因此,實際上通過優(yōu)化計算而不是存儲來對數(shù)據(jù)進(jìn)行建模是非常有意義的。
 

SQL數(shù)據(jù)庫中的數(shù)據(jù)存儲示例
將此數(shù)據(jù)模型轉(zhuǎn)換為NoSQL數(shù)據(jù)庫,例如DynamoDB,然后它看起來像下面這樣。

NoSQL數(shù)據(jù)庫(DynamoDB)的對應(yīng)數(shù)據(jù)存儲示例
解決水平擴(kuò)展
關(guān)系數(shù)據(jù)庫之所以很難水平擴(kuò)展的主要原因是查詢語法的靈活性。由于數(shù)據(jù)訪問模式的靈活性,系統(tǒng)不知道哪些數(shù)據(jù)將在查詢實際執(zhí)行之前被獲取。因此,為了避免在執(zhí)行查詢時進(jìn)行跨機(jī)器網(wǎng)絡(luò)調(diào)用,所有數(shù)據(jù)都必須保持在本地,即在同一節(jié)點上。
NoSQL數(shù)據(jù)庫通過要求將數(shù)據(jù)拆分為較小的段并在這些段之一中執(zhí)行所有查詢來采用水平擴(kuò)展。
為了更好地了解這一點,讓我們以user_id作為分區(qū)鍵,并在圖中進(jìn)行跟蹤。

大多數(shù)NoSQL數(shù)據(jù)庫在將分區(qū)鍵值分配給節(jié)點之前對其進(jìn)行哈希處理。這有助于更好地分發(fā)數(shù)據(jù)。
在讀取和寫入操作期間,所有查詢必須包括分區(qū)鍵,以便直接訪問相關(guān)節(jié)點。
解決查詢性能的不可預(yù)測性
在SQL數(shù)據(jù)庫中,隨著表的大小增長,操作會變得越來越慢。性能還受到同時運(yùn)行的其他查詢的影響。
對于NoSQL數(shù)據(jù)庫的讀取操作,所有查詢必須包括分區(qū)鍵。在執(zhí)行寫入操作時,可以將此操作發(fā)送到負(fù)責(zé)該數(shù)據(jù)塊的節(jié)點,而不會打擾群集中的其他節(jié)點。隨著數(shù)據(jù)量的增加,可以根據(jù)需要繼續(xù)添加額外的節(jié)點。每個操作僅影響群集中的一個節(jié)點。與SQL數(shù)據(jù)庫中的測試和生產(chǎn)環(huán)境相比,查詢性能幾乎不會有太大差異,因為每個操作僅影響一個節(jié)點。















 
 
 










 
 
 
 