通過本文,我們將了解數據庫如何擴展和不擴展。我們將研究傳統SQL數據庫存在的一些問題以及NoSQL數據庫的引入如何解決這些問題。
關于基本SQL的快速回顧
SQL(Structured Query Language)數據庫,也稱為關系數據庫,是一種基于關系模型的數據庫管理系統(DBMS)。它以結構化的方式組織和存儲數據,使用帶有行和列的表來表示實體及其關系。
SQL數據庫使用一種稱為SQL的結構化查詢語言與數據庫進行交互。SQL提供了一組命令和語法,用于定義、操作和檢索數據庫中的數據。使用SQL,您可以創建表,使用主鍵和外鍵定義表之間的關系,插入和更新數據,并查詢數據庫以檢索特定信息。
一些流行的SQL數據庫系統包括:
- MySQL → 一種廣泛用于Web應用程序的開源關系數據庫管理系統。
- PostgreSQL → 一種以其可擴展性和高級功能而聞名的開源面向對象關系數據庫。
- Microsoft SQL Server → 一種由Microsoft開發的商用RDBMS,通常用于基于windows的環境。
關于基本NoSQL的快速回顧
NoSQL數據庫,也稱為非關系數據庫,是一種與傳統SQL(Structured Query Language)數據庫不同的數據庫管理系統類型。
流行的NoSQL數據庫包括:
- MongoDB → 一種面向文檔的NoSQL數據庫,提供可伸縮性、靈活性和豐富的查詢功能。
- Cassandra → 一種高度可擴展和分布式的NoSQL數據庫,設計用于處理跨多個通用服務器的大量數據。
- redis → 一種支持鍵值數據存儲的內存型NoSQL數據庫,提供高速數據訪問。
- Amazon DynamoDB → 由Amazon Web Services(AWS)提供的全面托管的NoSQL數據庫服務,提供可伸縮性、高可用性和低延遲性能。
NoSQL數據庫通常用于需要處理大量快速變化的數據的情況,例如社交媒體平臺、物聯網應用程序等。
通過本文,我們將了解數據庫如何擴展和不擴展。我們將研究傳統SQL數據庫存在的一些問題以及NoSQL數據庫的引入如何解決這些問題。我們將涵蓋適合通過SQL數據庫解決的情況以及更適合NoSQL數據庫的情況。
關于關系數據庫的問題
關系數據庫適用于各種用例,并且通常是許多開發人員在開發應用程序時的默認選擇。此外,關系數據庫具有SQL,這使得可以在單個數據庫中處理新的訪問模式以及OLTP和OLAP模式成為可能。
- OLTP → 它代表在線事務處理。它指的是支持實時事務導向工作負載的一類計算機系統和應用程序。OLTP系統旨在通過處理大量的短時且快速的數據庫事務來促進和管理組織的日常運營活動。
- OLAP → 它代表在線分析處理。它指的是支持復雜數據分析、報告和決策任務的計算機系統和應用程序的一類。OLAP系統旨在處理大量數據并提供用于交互式和臨時分析的多維視圖。
OLTP vs OLAP[1] ← 這是一篇很好的文章,清晰地解釋了OLAP和OLTP的含義及其區別,并提供了兩者之間的簡潔比較。如果您想進一步了解,請查看。
然而,為了提供這些功能,關系數據庫通常遇到以下問題:
- 查詢性能的不可預測性
- 連接的問題
- 難以水平擴展的DB實例
查詢性能的不可預測性
在測試和應用程序生命周期的早期開發和發布階段,您的應用程序通常具有快速響應的查詢。
**帶有5GB數據的RDBMS數據存儲的表示**
然而,隨著表的大小增長,這些操作會變得越來越慢。性能還受到同時運行的其他查詢的影響。同時,如果公司的數據分析師在生產中對相同表進行分析操作,那么情況會變得更加復雜。
帶有500GB數據的RDBMS數據存儲的表示
這導致了第二個問題。
與所有著名的連接存在問題
SQL中的連接可以由于多種原因而損害速度:
- 大結果集 → 在執行連接操作時,如果連接的表之間有許多匹配行,結果集可能會顯著增長。這可能導致更大的中間結果集需要處理、傳輸和存儲,從而增加了內存消耗和較長的查詢執行時間。
- 缺乏索引使用 → 有效的連接操作通常依賴于連接列上適當索引的使用。如果缺少或未正確定義必要的索引以及外鍵,數據庫可能需要執行完整的表掃描或大量的磁盤I/O操作來定位匹配的行,從而導致性能較慢。
- 復雜的查詢計劃 → 數據庫優化器需要確定執行連接查詢的最有效方法。在某些情況下,查詢優化器可能需要考慮多個可能的連接路徑、表訪問方法和連接算法。這個過程可能變得復雜且耗時,特別是對于具有多個連接的查詢,可能導致次優查詢計劃和較慢的執行。
- 選擇性不足 → 包括非選擇性謂詞(匹配大部分數據的條件)的連接條件可能阻礙性能。非選擇性連接條件可能導致更大的中間結果集和較慢的查詢執行,因為數據庫需要處理大量數據以檢索所需的結果。
為了解決這些問題,您可能希望擴展數據庫,這將導致下一個問題。
DB實例的水平擴展難題
擴展數據庫有兩種方法:
- 垂直擴展 → 通過增加現有數據庫機器的CPU或RAM
- 水平擴展 → 通過向數據庫集群添加其他機器,每臺機器處理總數據的一個子集。
但是,您最終會達到垂直擴展的極限。在這一點上,您可能希望考慮水平擴展。但是,這會引入一套自己的挑戰。
- 數據分發和分片 → 在水平擴展時,跨多個節點分發數據至關重要。在SQL數據庫中,數據通常以具有關系和依賴關系的表結構化。拆分和分發這樣相互關聯的數據可能會很復雜,因為維護引用完整性并確保節點之間的一致數據變得具有挑戰性。通常會使用分片技術來將數據分區到節點上,但需要仔細規劃,可能會引入額外的復雜性。
- 查詢協調和連接 → SQL數據庫支持復雜的JOIN操作,以從多個表中檢索數據。當數據分布在節點之間時,執行JOIN操作變得更加具有挑戰性。連接可能需要節點之間的協調、網絡數據傳輸和增加的網絡延遲,可能影響性能和可伸縮性。
- 索引和查詢優化 → SQL數據庫在高效的數據檢索方面嚴重依賴于索引。隨著水平擴展,索引變得更加復雜,因為需要在節點之間分布和維護索引。由于數據的分布性質,查詢優化技術也變得更加具有挑戰性,可能影響查詢性能。
水平擴展在您可以分區單個請求可以由單個機器/節點處理的方式時效果最佳。
通過NoSQL數據庫解決方案
NoSQL數據庫嘗試解決關系數據庫提出的這些主要問題。
- 與所有著名的連接存在問題
- 查詢性能的不可預測性
- DB實例的水平擴展難題
解決連接
讓我們迅速了解NoSQL在這里試圖解決什么。
SQL依賴于規范化來進行數據建模。
規范化是數據庫設計中的一個過程,通過它來組織和結構化數據,以最小化冗余,提高數據完整
性,并優化數據庫效率。它涉及將數據分解為較小、更可管理的實體(表),并在它們之間建立關系。
它旨在通過只在一個地方存儲每個數據片段來消除冗余。這以以下方式使我們受益:
- 靈活的查詢 → 連接允許您通過單個操作從不同表中重新組裝所需的數據。有了連接的靈活性和SQL的其他語法糖,您不需要提前考慮如何訪問數據。您根據規范化的原則來建模實體,然后編寫查詢以處理您的需求。
- 增強數據完整性 → 規范化通過定義約束和表之間的關系來幫助實施數據完整性規則。主鍵和外鍵用于建立關系和強制引用完整性,防止數據不一致并確保數據完整性。
- 提高存儲效率 → 冗余數據,即相同信息存儲在多個地方,可能導致不一致和浪費存儲空間。只在一個地方存儲每個數據片段可以降低數據不一致的機會,并提高數據準確性。
然而,所有這些都需要付出代價。CPU和內存的代價通常很高。
NoSQL采用了解決所有這些問題的方法。
- 解決靈活的查詢NoSQL數據庫通過要求您事先制定所有主要數據訪問模式并設計數據庫以處理這些問題來避免您在數據訪問時靈活性的需求。您不需要在讀取時匯總數據,而是通過以讀取方式布置數據的方式存儲數據的預連接版本。
- 解決數據完整性NoSQL數據庫將數據完整性的責任推到了應用程序中。您需要將數據去規范化并復制到數據庫中。在更改時,可能需要更新包含相同數據的多個記錄。
- **解決存儲效率**NoSQL數據庫的存儲效率不如其關系對手高。但是,當設計RDBMS時,存儲費用相對于計算來說非常昂貴。與當前情況相比,存儲價格已經大幅下降,計算則成為首選。因此,實際上通過優化計算而不是存儲來對數據進行建模是非常有意義的。
SQL數據庫中的數據存儲示例
將此數據模型轉換為NoSQL數據庫,例如DynamoDB,然后它看起來像下面這樣。
NoSQL數據庫(DynamoDB)的對應數據存儲示例
解決水平擴展
關系數據庫之所以很難水平擴展的主要原因是查詢語法的靈活性。由于數據訪問模式的靈活性,系統不知道哪些數據將在查詢實際執行之前被獲取。因此,為了避免在執行查詢時進行跨機器網絡調用,所有數據都必須保持在本地,即在同一節點上。
NoSQL數據庫通過要求將數據拆分為較小的段并在這些段之一中執行所有查詢來采用水平擴展。
為了更好地了解這一點,讓我們以user_id作為分區鍵,并在圖中進行跟蹤。
大多數NoSQL數據庫在將分區鍵值分配給節點之前對其進行哈希處理。這有助于更好地分發數據。
在讀取和寫入操作期間,所有查詢必須包括分區鍵,以便直接訪問相關節點。
解決查詢性能的不可預測性
在SQL數據庫中,隨著表的大小增長,操作會變得越來越慢。性能還受到同時運行的其他查詢的影響。
對于NoSQL數據庫的讀取操作,所有查詢必須包括分區鍵。在執行寫入操作時,可以將此操作發送到負責該數據塊的節點,而不會打擾群集中的其他節點。隨著數據量的增加,可以根據需要繼續添加額外的節點。每個操作僅影響群集中的一個節點。與SQL數據庫中的測試和生產環境相比,查詢性能幾乎不會有太大差異,因為每個操作僅影響一個節點。