+20

[Phỏng vấn Backend]: PostgreSQL vs MongoDB, nên chọn database nào?

I. Giới thiệu

Đợt phỏng vấn, anh tech lead hỏi mình tại sao dùng mongodb cho dự án cũ mà không phải là postgres (kinh nghiệm của mình có 2 loại database này). Mình kể một thôi một hồi thứ hay ho của mongodb ra, nào là json based, đọc ghi nhanh này kia... Xong anh tech lead hỏi thế postgres không làm được à? Giờ anh bỏ relationship của thằng postgres đi thì có khác gì mongodb không. Lúc đó đứng hình luôn 😃). Một khoảng thời gian nữa học và làm thì mình nhận ra được một vài điều về 2 thằng database này. Nếu được hỏi lại câu hỏi đó mình sẽ trả lời là "Về cơ bản dùng thằng cũng đáp ứng được nhu cầu thôi. Nhưng sẽ có thằng làm tốt hơn thằng khác ở những case cụ thể, nếu sử dụng đúng thì sẽ nhanh và hiệu quả hơn, tiết kiệm chi phí cho dự án hơn..."

II. Các yếu tố cần xem xét trước khi lựa chọn

  • Độ phù hợp với dự án: Đánh giá yêu cầu cụ thể của dự án và xem database nào đáp ứng tốt nhất.
  • Chi phí: Xem xét chi phí triển khai, vận hành và khả năng tài chính của dự án.
  • Kinh nghiệm team: Đánh giá thế mạnh và kinh nghiệm của team phát triển.
  • Cộng đồng và hỗ trợ: Xem xét quy mô cộng đồng và mức độ hỗ trợ có sẵn.
  • Tích hợp: Đánh giá khả năng tích hợp với các công nghệ/framework hiện tại.

III. So sánh chi tiết

1. Đọc (Read)

  • PostgreSQL: Khả năng đọc tốt vì sử dụng cơ chế Multi version concurrency control (MVCC). Ví dụ khi update 1 bản ghi, postgres không thực chất update lên record cũ mà nó insert 1 record mới vào database, record cũ được đánh dấu là không còn hiệu lực, rồi sử dụng VACUUM để dọn dẹp định kì những dữ liệu dư thừa. Việc tạo record mới này giúp cho hoạt động đọc đồng thời diễn ra mà không bị gián đoạn khi người dùng có thể đọc được phiên bản cũ của record trong khi phiên bản record mới đang được thêm vào. So sánh với 1 thằng anh em trong SQL là mySQL thì thằng này sẽ update trực tiếp vào record đó luôn, nên hiệu suất đọc của nó sẽ bị kém hơn so với postgres.
  • MongoDB: khả năng đọc rất tốt với dữ liệu phi cấu trúc.

2. Ghi (Write)

  • PostgreSQL: Mặc dù cơ chế MVCC cải thiện hiệu suất đọc, nhưng nó có thể tạo ra một số overhead cho các hoạt động ghi, vì cần tạo ra phiên bản mới của dữ liệu. Do đó nếu đem so với MySQL hay MongoDB thì khả năng ghi của nó không mạnh bằng.
  • MongoDB: Khi update nếu dữ liệu mới nếu data mới có dung lượng bằng hoặc nhỏ hơn data cũ thì nó sẽ update trực tiếp lên vùng nhớ đó. Còn nếu vùng nhớ đó không đủ thì nó sẽ tìm một vị trí khác rồi đặt dữ liệu vào đó. Dữ liệu cũ sẽ được đánh dấu là không hiệu lực, giống giống với postgres ha. Ưu điểm của phương pháp này là giúp giảm thời gian I/O trên đĩa, giảm thiểu việc cập nhật lại index. Do đó nên mongoDB có ưu thế trong các thao tác ghi đơn lẻ, QPS cao (2000-3000 request/s). Ngoài ra từ phiên bản 3.2, mongodb cung cấp nén dữ liệu và kiểm soát đồng thời ở cấp độ document, góp một phần vào hiệu suất cao của nó.

3. Cơ chế lưu trữ

  • MongoDB hỗ trợ hai loại storage engine chính:

WiredTiger (Mặc định từ phiên bản 3.2)

  • Hỗ trợ lưu trữ trên đĩa
  • Cung cấp nén dữ liệu và index
  • Hỗ trợ document-level concurrency
  • Cung cấp cả unjournal và journal storage. Thằng journal này giống như một cuốn sổ nhật ký ghi lại các thao tác, thường là các thay đổi về byte trên các trang dữ liệu. Journal được đồng bộ hóa thường xuyên (mặc định là 100ms), giúp giảm thiểu mất mát dữ liệu trong trường hợp sự cố.

In-Memory

  • Lưu trữ dữ liệu hoàn toàn trong bộ nhớ RAM (chắc thằng này muốn cạnh tranh với redis nên đẻ ra thêm storage engine này), nhưng bản enterprise mới có.
  • Tối ưu cho các ứng dụng yêu cầu độ trễ cực thấp
  • Không duy trì sau khi tắt server

PostgreSQL sử dụng một kiến trúc storage engine duy nhất, nhưng có nhiều tùy chọn và extension:

Heap Storage Engine (Mặc định)

  • Sử dụng cấu trúc heap để lưu trữ dữ liệu
  • Hỗ trợ MVCC (Multi-Version Concurrency Control)
  • Sử dụng WAL (Write-Ahead Logging) để đảm bảo tính bền vững: thằng này giống như cuốn sổ cái log lại toàn bộ thao tác trên database trước khi nó được lưu vào database.
    • Mặc định là nó đi liền với database, không có vụ thích thì tắt giống bên Mongodb được. Việc này giúp đảm bảo tính ACID hơn so với mongoDB.
    • Khác một chút so với Journal của mongodb là nó ghi lại các thao tác ở mức độ cao hơn, thường là các câu lệnh SQL hoặc các thay đổi ở mức logic.
    • WAL được đồng bộ hóa tùy thuộc vào cấu hình (ví dụ: sau mỗi giao dịch hoặc theo khoảng thời gian).
    • Nhìn chung thì thằng WAL này khá là mạnh, ngoài khôi phục sau sự cố, còn được sử dụng cho sao chép (replication) và khôi phục điểm thời gian (point-in-time recovery).... trong khi journal thường chỉ được dùng để khôi phục dữ liệu sau sự cố.

Extensions và Tùy chọn Lưu trữ

  • TOAST (The Oversized-Attribute Storage Technique): Cho phép lưu trữ hiệu quả các giá trị lớn
  • Tablespaces: Cho phép lưu trữ dữ liệu trên các thiết bị vật lý khác nhau
  • pg_trgm: Hỗ trợ tìm kiếm văn bản nhanh chóng
  • PostGIS: Extension cho dữ liệu không gian địa lý

Các plugin bên thứ ba

  • Citus: Cho phép sharding và phân tán dữ liệu, tuy nhiên hàng extension thì không thể ngon bằng mongo được rồi
  • TimescaleDB: Tối ưu hóa cho dữ liệu chuỗi thời gian

In-Memory Options

  • Mặc dù không có storage engine in-memory riêng biệt, PostgreSQL cung cấp:
  • Shared Buffers: Cache dữ liệu trong RAM
  • pg_prewarm: Tải dữ liệu vào bộ nhớ trước khi sử dụng
  • Temporary tables in RAM: Cho phép tạo bảng tạm thời trong bộ nhớ

4. Đánh index

  • PostgreSQL: hỗ trợ nhiều loại index như (hash index, b-tree, GiST, SP-GiST, GIN, BRIN, Partial Index, Expression Index)
  • MongoDB: cũng nhiều không kém (Single Field Index, Compound Index, multikey Index, Geospatial Index, Text Index, Hashed Index, Wildcard Index, Partial Index, TTL (Time-To-Live) Index, Unique Index)

5. Join

PostgreSQL:

  • Sử dụng các thuật toán join hiệu quả như nested loop, hash join, và merge join.
  • Tự động chọn thuật toán join tối ưu dựa trên thống kê dữ liệu và cấu trúc index.
  • Hỗ trợ subqueries trong mệnh đề JOIN.
  • Sử dụng index để tăng tốc join.
  • Cho phép tùy chỉnh các tham số như work_mem để tối ưu hóa hiệu suất join.

MongoDB:

  • $lookup (từ phiên bản 3.2), Tương đương với LEFT OUTER JOIN trong SQL nhưng chỉ hỗ trợ join giữa 2 collection. Từ phiên bản 3.6, MongoDB hỗ trợ $lookup với nhiều collection, nhưng vẫn hạn chế so với SQL joins.
  • Thay vì sử dụng join, MongoDB khuyến khích sử dụng embedded documents để lưu trữ dữ liệu liên quan. Trong nhiều trường hợp, join được thực hiện ở phía ứng dụng thay vì trong database.
  • Thường sử dụng kỹ thuật denormalization để tránh nhu cầu join.

6. Khả năng mở rộng

  • Mở rộng dọc: Cả hai đều hỗ trợ tốt.
  • Mở rộng ngang: MongoDB có ưu thế với sharding tích hợp sẵn. PostgreSQL có các giải pháp mở rộng ngang như Citus (hiện là một phần chính thức của PostgreSQL) và PgPool-II. Tuy nhiên là các giải pháp này không được tích hợp sẵn như MongoDB, nó cũng phức tạp hơn trong việc triển khai và quản lý.

7. Hỗ trợ JSON

  • Cả hai đều hỗ trợ JSON, nhưng MongoDB có ưu thế hơn do bản chất document-based.

8. Full-text search

PostgreSQL:

  • Có các loại index chuyên biệt như GiST, SP-GiST, và GIN (Generalized Inverted Index), rất hữu ích cho các loại dữ liệu phức tạp và tìm kiếm full-text.
  • tsvectortsquery cho full text indexing và searching.
  • Có thư viện pg_trgm hỗ trợ tìm kiếm văn bản nhanh chóng.
  • MongoDB có tích hợp sẵn full-text search engine từ phiên bản 2.4. MongoDB Atlas (dịch vụ đám mây chính thức của MongoDB) cung cấp Atlas Search, một giải pháp full-text search mạnh mẽ tích hợp sẵn dựa trên Apache Lucene (cũng là core của Elasticsearch). Nó cũng hỗ trợ mạnh mẽ cho việc tìm kiếm theo địa lý.

Nhìn chung cả hai đều có thể đáp ứng tốt nhu cầu full-text search cho nhiều ứng dụng, nhưng có thể cần giải pháp bổ sung (như Elasticsearch) cho các ứng dụng có yêu cầu tìm kiếm phức tạp và khối lượng lớn.

9. Hỗ trợ ACID

  • PostgreSQL được xây dựng từ đầu với mục tiêu tuân thủ chặt chẽ các nguyên tắc ACID. Bên cạnh đó PostgreSQL có thể xử lý hiệu quả các giao dịch phức tạp mà không ảnh hưởng nhiều đến hiệu suất.
  • MongoDB hỗ trợ ACID từ phiên bản 4.0, nhưng có một số hạn chế. Transaction trong MongoDB có giới hạn về thời gian và kích thước, để tránh ảnh hưởng đến hiệu suất tổng thể. Không hỗ trợ savepoints như trong các RDBMS truyền thống.

10. Cộng đồng hỗ trợ

  • Cả MongoDB và PostgreSQL đều có cộng đồng lớn và tích cực.
  • PostgreSQL có lợi thế về thời gian tồn tại lâu dài và sự ổn định.
  • MongoDB có sự phát triển nhanh chóng trong cộng đồng NoSQL.

IV. Kết luận

1. Khi nào chọn mongoDB

  • Ít sử dụng transaction.
  • Mô hình dữ liệu thường xuyên thay đổi.
  • Yêu cầu QPS cao (2000-3000 request/s).
  • Xử lý lượng dữ liệu lớn hàng ngày, có khả năng phân tích thời gian thực (real-time analytics). (ví dụ: IoT).
  • Team nhỏ, cần phát triển dự án nhanh chóng.
  • Cần khả năng mở rộng dễ dàng (replica set, sharding).
  • Yêu cầu truy vấn địa lý (location queries).
  • Dữ liệu có cấu trúc lồng nhau phức tạp (nested model).
  • Xử lý dữ liệu phi cấu trúc hoặc bán cấu trúc.

2. Khi nào chọn PostgreSQL

  • Ưu tiên tính ổn định và độ tin cậy của dữ liệu hơn là tốc độ ghi cực cao
  • Cần hiệu suất đọc cao, đặc biệt cho các truy vấn phức tạp
  • Dữ liệu có cấu trúc rõ ràng và ít thay đổi.
  • Cần thực hiện các truy vấn phức tạp, đặc biệt là các truy vấn liên quan đến nhiều bảng (joins)
  • Yêu cầu tuân thủ nghiêm ngặt các quy định về dữ liệu (ví dụ: trong lĩnh vực tài chính, y tế).

Tóm lại, MongoDB thích hợp cho các ứng dụng cần xử lý dữ liệu lớn, không cấu trúc, và yêu cầu khả năng mở rộng cao. PostgreSQL phù hợp cho các ứng dụng cần độ tin cậy cao, có cấu trúc dữ liệu phức tạp và yêu cầu nhiều truy vấn phân tích. Việc lựa chọn cuối cùng phụ thuộc vào yêu cầu cụ thể của dự án, kinh nghiệm của team, và các ràng buộc về ngân sách và thời gian.

Tham khảo

Group discord 2k+ mems: chém gió về lập trình và làm pet project cùng nhau tips javascript | wecommit


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí