Logo Wecommit
Về chúng tôiCộng đồngLời chứng thựcTài nguyên
Logo Wecommit

PostgreSQL vs MySQL: hiệu năng khi CCU lớn và truy vấn nặng

Chọn PostgreSQL hay MySQL? Khác biệt thật nằm ở cách hai ông làm MVCC và cách bộ tối ưu dựng chiến lược thực thi. Bài chỉ rõ hoàn cảnh nào chọn ông nào.

PostgreSQL vs MySQL, chọn ông nào? Đây là câu anh em tra Google nhiều nhất trong mảng cơ sở dữ liệu. Phần lớn câu trả lời ngoài kia là bảng liệt kê tính năng chép từ tài liệu, và bảng đó không giúp anh em quyết được gì. Bài này đi theo đúng cách tôi lập luận trong video: chỉ có hai câu hỏi thật sự quyết định, cả hai đều nằm ở kiến trúc bên trong.

Video gốc 32 phút, tôi vẽ tay toàn bộ cơ chế trên bảng. Bài viết giữ nguyên mạch đó, bổ sung phần đối chiếu tài liệu gốc và mục "Giới hạn thật".

Chọn PostgreSQL hay MySQL thì phải nhìn vào đâu?

Nhìn vào đúng hai thứ. Thứ nhất, khi người dùng đồng thời tăng cao, rất nhiều giao dịch cùng chọc vào một bảng, thì ông nào chịu tải tốt hơn. Thứ hai, khi hệ thống chạy báo cáo nặng, câu lệnh SQL dài hàng trang giấy, join tùm lum, thì ông nào ra kết quả nhanh hơn.

Dữ liệu ít, câu lệnh đơn giản thì không chấp, chọn ông nào cũng được. Còn hai câu hỏi trên thì gốc rễ nằm ở hai chỗ khác hẳn nhau trong kiến trúc:

Câu hỏiGốc rễ nằm ở đâuAi thắng
Nhiều người ghi cùng lúc, ông nào chịu được?Cơ chế MVCC, tức cách lưu nhiều phiên bản của một dòng dữ liệuMySQL
Câu lệnh phân tích phức tạp, ông nào nhanh hơn?Bộ tối ưu, tức cách dựng chiến lược thực thiPostgreSQL

Hai dòng đó là toàn bộ bài viết này. Phần còn lại là tôi chứng minh vì sao.

MVCC là gì và vì sao nó quyết định hiệu năng khi CCU lớn?

MVCC là cơ chế cho phép nhiều phiên cùng đọc ghi một dòng dữ liệu mà không chặn nhau, bằng cách giữ đồng thời nhiều phiên bản của dòng đó. Đây là thứ quyết định hệ thống sống hay chết khi lượng truy cập đồng thời tăng lên.

Anh em hình dung cho dễ. Trong database có ông Huy, lương 1000 đô. Phiên thứ nhất gõ update đổi lương lên 1500 nhưng chưa commit. Cùng lúc đó phiên thứ hai gõ select, và nó phải nhìn thấy 1000. Còn phiên thứ nhất, chính nó vừa gõ update xong, phải nhìn thấy 1500.

Cùng một dòng, cùng một thời điểm, ông này ra 1500, ông kia ra 1000. Làm sao được như thế? Đó chính là việc của MVCC.

Tài liệu PostgreSQL gọi cái lợi lớn nhất của mô hình này là: đọc không bao giờ chặn ghi, ghi không bao giờ chặn đọc. Tài liệu MySQL nói y hệt về InnoDB.

Đến đây hai ông giống nhau. Nhưng cách làm ra kết quả đó thì khác nhau hoàn toàn. Vì khác nhau nên hiệu năng cũng khác nhau luôn.

PostgreSQL xử lý một câu UPDATE như thế nào?

PostgreSQL không sửa đè lên dòng cũ. Nó thêm hẳn một dòng mới vào một vị trí vật lý khác, rồi trỏ ngược về dòng cũ.

Tôi lấy đúng cái bảng nhân viên trong video. Ba bản ghi: ông Huy lương 1000 ở Hà Nội, ông An lương 50 ở Nam Định, ông Bình lương 800 ở Hà Nam. Cột ID là primary key. Điều anh em ít để ý là PostgreSQL còn tự gắn thêm cột ctid, mô tả vị trí vật lý của dòng trên đĩa. Tôi gọi ba vị trí đó là ô A, ô B, ô C.

Bảng nhân viên trên bảng trắng với cột CTID màu xanh đứng trước cột ID, và index trên cột name trỏ An sang B, Bình sang C, Huy sang A
Cột CTID bên trái chính là vị trí vật lý. Góc phải: index cột name trỏ thẳng vào ô A, ô B, ô C. Nhớ kỹ chỗ này.

Thực tế làm dự án thì bảng nào cũng đẻ thêm index phụ. Giả sử có index trên cột name và trên cột salary. Index name lưu An, Bình, Huy theo chiều tăng dần, mỗi tên trỏ tới ô A, B, C tương ứng. Index salary lưu 50, 800, 1000, cũng trỏ tới ô vật lý.

Bây giờ update lương ông Huy lên 1500. PostgreSQL làm gì? Nó không sửa ô A. Nó ghi một dòng hoàn toàn mới vào ô D, đủ cả ID là 1, tên Huy, lương 1500, địa chỉ Hà Nội. Rồi nó tạo một con trỏ để biết dòng ở ô D vốn là bản thay đổi của dòng ở ô A. Có con trỏ đó thì lúc rollback mới quay về được.

Vì sao sửa cột lương mà index cột tên cũng phải đổi?

Vì trong PostgreSQL, mọi index đều trỏ thẳng tới vị trí vật lý của dòng. Dòng chuyển sang ô mới thì mọi index đều phải trỏ lại.

Đây là chỗ nhọ. Anh em nhìn kỹ nhá:

  • Index salary phải thêm giá trị 1500 trỏ vào ô D. Bản ghi 1000 cũ vẫn nằm đó, chưa xóa.
  • Index name cũng phải thêm một mục Huy trỏ vào ô D. Trong khi ta có động vào cột name đâu.
  • Index primary key cũng phải thêm một mục ID bằng 1 trỏ vào ô D.
Bảng trắng sau khi update trong PostgreSQL, thêm dòng D lương 1500, ba index đều phải thêm mục trỏ vào D và gạch bỏ mục cũ
Dòng D là bản ghi mới. Ba cụm index bên phải đều phải thêm mục trỏ vào D. Một câu update, ba index phải sờ vào.

Chúng ta chỉ cập nhật mỗi cột salary, cột name không đụng tới một chữ. Vậy mà index của cột name vẫn bị cập nhật theo, chỉ vì giá trị Huy giờ phải trỏ vào một ô khác.

Đội kỹ thuật của Uber gọi hiện tượng này là write amplification, tức khuếch đại ghi. Trong bài viết giải thích vì sao họ chuyển từ Postgres sang MySQL, họ đếm ra một lần sửa năm sinh của một bản ghi kéo theo ít nhất bốn lần ghi vật lý. Và họ nói thẳng: bảng nào có một tá index thì một lần sửa cột chỉ nằm trong một index sẽ phải lan ra cả mười hai index. Đúng bài toán tôi vẽ trên bảng, chỉ khác là ở quy mô Uber.

Vacuum dọn dẹp ở đâu và vì sao chỗ đó quan trọng?

Vacuum dọn ngay trên chính cái bảng đang phục vụ người dùng. Đó là khác biệt lớn nhất so với MySQL.

Những dòng cũ không ai còn cần thì phải có ai đó dọn đi. PostgreSQL giao việc đó cho tiến trình vacuum, chạy tự động và định kỳ. Tài liệu PostgreSQL ghi rõ hai điều đáng nhớ. Một là vacuum tạo ra lượng I/O đáng kể, làm các phiên đang chạy chậm đi. Hai là nó thường không trả dung lượng về cho hệ điều hành, chỉ đánh dấu chỗ trống để dùng lại.

Nghĩa là trước khi vacuum kịp chạy, hệ thống phải chứa nhiều hơn thực tế nó có. Bảng chỉ 5.000 bản ghi thật, nhưng update liên tục thì nó có thể phình lên 10.000 hay 15.000. Index cũng phình theo. Tôi có phân tích riêng cơ chế này trong bài Vacuum trong PostgreSQL ảnh hưởng tới hiệu năng thế nào.

MySQL xử lý cùng câu UPDATE đó ra sao?

MySQL sửa đè trực tiếp lên dòng cũ, còn giá trị cũ thì nó vứt sang một vùng riêng gọi là undo tablespace. Cùng cái bảng đó, cùng câu lệnh đổi 1000 thành 1500, nhưng tư duy của InnoDB khác hẳn: không nhét mọi phiên bản vào chung một bảng.

Bảng trắng ghi chữ MySQL, lương ông Huy được sửa đè thành 1500 ngay trong bảng, còn giá trị cũ 1000 nằm trong khung Undo bên phải
Ô lương sửa đè thẳng thành 1500. Giá trị cũ 1000 chạy sang khung Undo bên phải, chỗ mũi tên rollback quay về.

Ai gõ rollback thì nó lấy dữ liệu từ vùng undo ra khôi phục. Ai đang trong phiên update thì thấy 1500. Ai ở ngoài thì nó dẫn sang vùng undo, thấy 1000. Cùng một bài toán, giải bằng cách chia góc nhìn chứ không chất đống vào một chỗ.

Tài liệu MySQL mô tả đúng cơ chế này: mỗi dòng có thêm trường DB_ROLL_PTR trỏ vào bản ghi undo, và bản ghi undo thường nhỏ hơn chính dòng dữ liệu đã sửa.

Vì sao index của MySQL không bị cuốn theo?

Vì secondary index của InnoDB không trỏ vào vị trí vật lý. Nó trỏ vào giá trị primary key.

Đây là câu quan trọng nhất của cả bài. Index name của MySQL lưu An, Bình, Huy, nhưng ba mục đó không trỏ vào ô A, ô B, ô C. Chúng trỏ vào ID 2, ID 3, ID 1. Mà ID thì không đổi khi ta sửa lương. Nên index name không phải sờ vào, primary key cũng không. Cập nhật cột salary thì đúng một mình index salary phải đổi. Hết.

Bảng trắng MySQL, index trên cột name trỏ An sang 2, Bình sang 3, Huy sang 1 và không bị sửa, chỉ index salary được khoanh tròn là phải đổi
Index name trỏ vào ID chứ không vào ô vật lý nên nó nằm im. Chỉ cụm được khoanh tròn, tức index salary, phải đổi.

Tài liệu MySQL về clustered và secondary index viết đúng như vậy: mỗi bản ghi trong secondary index chứa các cột primary key của dòng, và InnoDB dùng giá trị đó để tìm dòng trong clustered index.

Cái giá phải trả là tra cứu qua secondary index phải đi qua hai cây index thay vì một. Đổi lại, ghi nhẹ hơn hẳn.

Bảng đối chiếu MVCC hai ông

ThứPostgreSQLMySQL với InnoDB
Update một dòngGhi hẳn dòng mới ở vị trí vật lý khácSửa đè tại chỗ
Bản cũ nằm đâuNằm chung trong chính bảng dữ liệuNằm ở undo tablespace, tách riêng
Index trỏ vào gìVị trí vật lý của dòng, tức ctidGiá trị primary key
Sửa một cột có indexMọi index đều phải thêm mục mớiChỉ index của cột đó phải đổi
Ai dọn rácTiến trình vacuumTiến trình purge
Dọn ở đâuNgay trên bảng đang phục vụTrên vùng undo, tách khỏi bảng chính
Ảnh hưởng lúc dọnCó, vì chung chỗ với bảng chínhNhẹ hơn, vì khác phân vùng

Chốt lại. Hệ thống nào ghi rất nhiều, bảng lại đeo nhiều secondary index, thì PostgreSQL sẽ chậm hơn MySQL. Không phải vì ông nào dở hơn ông nào. Là vì kiến trúc hai ông vốn khác nhau từ gốc.

Một câu SQL chạy qua mấy bước, bước nào ăn hiệu năng?

Sáu bước. Và chỉ có bước bốn với bước năm là ăn hiệu năng thật sự. Database nào cũng cùng một mạch này:

  1. Check cú pháp. Viết select mà quên from thì nó báo lỗi ngay.
  2. Check ngữ nghĩa. Bảng đó có thật không, cột đó có trong bảng không, user này có quyền không.
  3. Kiểm tra xem chiến lược thực thi đã có sẵn trong bộ nhớ chưa. Có rồi thì chạy luôn.
  4. Phân tích chiến lược thực thi. Có bao nhiêu đường đi, mỗi đường tốn bao nhiêu.
  5. Tạo ra chiến lược thực thi, chọn đường có cost nhỏ nhất.
  6. Thực thi.
Sơ đồ sáu bước thực thi một câu lệnh SQL vẽ tay, bước 1 cú pháp, bước 2 ngữ nghĩa, bước 4 và 5 phân tích và tạo ra chiến lược có cost nhỏ nhất
Bước 4 và bước 5 là chỗ tôi khoanh xanh "cost nhỏ nhất". Khác biệt giữa hai database nằm gọn trong đó.

Hai bước đầu thì database nào cũng như nhau. Bước ba liên quan tới bộ nhớ đệm chiến lược, tôi có chia sẻ riêng trong bài Tối ưu SQL: cùng một câu lệnh nhưng lúc nhanh, lúc chậm.

Bước bốn và bước năm mới là nơi hai ông tách nhau ra. Anh em hình dung đi từ điểm A tới điểm B có n con đường. Có đường vòng, có đường tắc, có đường phí cao. Việc của bộ tối ưu là đánh giá hết chỗ đó rồi chọn con đường rẻ nhất. Đúng như tài liệu PostgreSQL viết: bộ tối ưu duyệt các phương án và chọn phương án được ước lượng là chạy nhanh nhất.

Đây cũng là lý do đôi khi anh em chỉ nâng phiên bản database thôi, chưa hề đổi loại, mà hiệu năng đã khác hẳn. Vì cái được nâng chính là bộ tối ưu này. Nâng MySQL từ 5.7 lên 8.0 là thấy ngay, tôi có phân tích riêng trong bài Hiệu năng MySQL 8: nâng cấp lớn trong Query Optimizer.

Vì sao PostgreSQL nhanh hơn ở câu lệnh phân tích phức tạp?

Vì bộ tối ưu của PostgreSQL dùng nhiều yếu tố đầu vào hơn để tính cost, và nó dám viết lại câu lệnh của anh em.

PostgreSQL viết lại câu lệnh của anh em như thế nào?

Nó biến subquery thành join khi thấy làm vậy rẻ hơn.

Giả sử anh em có câu subquery trên bảng customers với bảng orders. Logic viết ra là chạy câu bên trong trước, xong mới ra ngoài. MySQL làm rất đơn phương, đúng y như anh em viết. PostgreSQL thì không. Nó tự viết lại thành hash join, dù câu lệnh chẳng có chữ join nào.

Kết quả explain analyze của PostgreSQL, node trên cùng là Hash Join với actual time 0.039 tới 0.041, bên dưới là Planning Time 0.186 ms và Execution Time 0.073 ms
Node trên cùng ghi thẳng Hash Join. Câu lệnh tôi gõ là subquery, không có chữ join nào. Bộ tối ưu tự dựng ra nó.

Trong demo của tôi, cùng một câu lệnh, cùng cấu trúc bảng, cùng dữ liệu, chạy trên hai database:

DatabaseCách nó chọnActual time của node trên cùng
PostgreSQLTự chuyển thành hash join0,039 tới 0,041 ms
MySQLChạy tuần tự đúng thứ tự câu lệnh0,355 tới 0,37 ms
Hai kết quả explain analyze đặt chồng nhau, phía trên ghi tay chữ PG màu cam, phía dưới ghi tay chữ MySQL màu xanh lá với các node Table scan và Materialize with deduplication
Khối dưới là MySQL. Nó đi đúng thứ tự tôi viết: quét bảng, gom bảng tạm, rồi tra ngược ra ngoài. Rất đơn phương.

Anh em đừng quan trọng hóa con số này. Dữ liệu demo rất nhỏ, một câu lệnh, một máy, không phải benchmark. Điều đáng nhớ là cơ chế: PostgreSQL dám chuyển câu lệnh sang kiểu join khác. Câu lệnh càng phức tạp thì bước chuyển đổi này càng cho hiệu quả rõ rệt.

Muốn tự nhìn thấy chuyện này trên hệ thống của mình thì dùng explain và explain analyze. Tôi có chia sẻ cách đọc trong bài Tối ưu MySQL với Explain và Explain Analyze.

Bộ kiểu join và kiểu index của hai ông khác nhau ra sao?

PostgreSQL hỗ trợ đủ ba kiểu join từ lâu, còn MySQL mới có thêm hash join gần đây.

Tài liệu PostgreSQL liệt kê ba chiến lược join: nested loop join, merge join, hash join. Bộ tối ưu cân cả ba rồi chọn cái rẻ nhất. Phía MySQL, các phiên bản cũ chủ yếu chỉ chạy nested loop. Tài liệu MySQL ghi rõ mốc: từ 8.0.18 mới bắt đầu dùng hash join, tới 8.0.20 thì bỏ hẳn block nested loop.

Về index cũng vậy. PostgreSQL có B-tree, Hash, GiST, SP-GiST, GIN, BRIN. MySQL thì cú pháp CREATE INDEX chỉ cho USING BTREE hoặc USING HASH, kèm hai loại riêng là FULLTEXT và SPATIAL. Nhiều lựa chọn hơn nghĩa là bộ tối ưu có nhiều con đường hơn để cân. Anh em nào muốn hiểu vì sao có index rồi mà câu lệnh vẫn chậm thì đọc thêm bài Vì sao có Index mà câu SQL vẫn chậm và bài Tầm quan trọng của thứ tự các cột trong Index PostgreSQL.

Chốt lại, hoàn cảnh nào chọn ông nào?

Hoàn cảnh hệ thống của anh emNên nghiêng về
Ghi nhiều, update liên tục, bảng đeo nhiều secondary indexMySQL
Người dùng đồng thời cực lớn, chủ yếu giao dịch ngắnMySQL
Báo cáo nặng, câu lệnh nhiều join, nhiều subqueryPostgreSQL
Cần nhiều kiểu index đặc thù, tìm kiếm không gianPostgreSQL
Câu lệnh đơn giản, dữ liệu nhỏÔng nào cũng được

Tự kiểm trên hệ thống của mình bằng gì?

Chép bộ câu lệnh này về chạy luôn, nó trả lời đúng câu hỏi hệ thống của mình đang rơi vào bên nào.

-- [1] PostgreSQL: xem chiến lược thực thi thật của một câu lệnh
EXPLAIN (ANALYZE, BUFFERS) SELECT ... ;

-- [2] PostgreSQL: bao nhiêu phần trăm update phải sờ vào index
-- n_tup_hot_upd cang gan n_tup_upd thi cang do
SELECT relname, n_tup_upd, n_tup_hot_upd,
       round(100.0 * n_tup_hot_upd / NULLIF(n_tup_upd,0), 1) AS ty_le_hot
FROM   pg_stat_user_tables
ORDER  BY n_tup_upd DESC
LIMIT  10;

-- [3] PostgreSQL: bang nao dang phinh vi ban cu chua duoc don
SELECT relname, n_live_tup, n_dead_tup, last_autovacuum, last_autoanalyze
FROM   pg_stat_user_tables
ORDER  BY n_dead_tup DESC
LIMIT  10;

-- [4] PostgreSQL: dem so index dang deo tren mot bang
SELECT tablename, indexname FROM pg_indexes WHERE tablename = 'ten_bang';

-- [5] MySQL 8: xem chien luoc thuc thi that
EXPLAIN ANALYZE SELECT ... ;

-- [6] MySQL: undo co bi ton lai khong, so cang lon cang do
SELECT NAME, COUNT
FROM   information_schema.INNODB_METRICS
WHERE  NAME = 'trx_rseg_history_len';

-- [7] MySQL: dem so index dang deo tren mot bang
SELECT INDEX_NAME, COLUMN_NAME
FROM   information_schema.STATISTICS
WHERE  TABLE_SCHEMA = 'ten_schema' AND TABLE_NAME = 'ten_bang';

Chạy câu số 2 trước. Tỷ lệ HOT thấp mà số index lại cao, đó chính là hoàn cảnh PostgreSQL trả giá đắt nhất cho mỗi lần ghi.

Giới hạn thật

Phần này quan trọng ngang cả bài. Đọc kỹ trước khi mang kết luận đi quyết định.

Video quay tháng 06/2024, hai ông đã đi tiếp. Câu "MySQL chỉ hỗ trợ nested loop" đúng với các phiên bản cũ. Từ 8.0.18 MySQL đã có hash join, từ 8.0.20 bỏ hẳn block nested loop. Chạy MySQL 8 bản mới thì khoảng cách ở câu lệnh phân tích hẹp lại nhiều.

PostgreSQL có một cửa thoát tên là HOT mà tôi chưa nói trong video. Tài liệu PostgreSQL về heap-only tuples ghi rõ: nếu câu update không đụng cột nào đang được index, và trang chứa dòng cũ còn đủ chỗ, thì PostgreSQL không cần thêm mục index nào. Nhưng để ý điều kiện đó. Trong ví dụ của tôi cột salary có index, nên HOT không cứu được.

Bài của Uber dựa trên PostgreSQL 9.2, viết năm 2016. Chính họ ghi chú điều đó. Đừng áp nguyên kết luận của họ vào một cụm PostgreSQL bản mới.

Hai con số 0,041 và 0,37 là demo, không phải benchmark. Đơn vị là mili giây, đọc thẳng từ màn hình, và là actual time của node trên cùng chứ không phải tổng thời gian chạy. Riêng PostgreSQL còn in Execution Time: 0.073 ms ở dòng dưới. Dữ liệu nhỏ, một lần chạy. Nó minh họa cơ chế chứ không đo năng lực hai hệ thống.

Toàn bộ phần MySQL trong bài giả định engine là InnoDB. Dùng engine khác thì mọi thứ về MVCC ở trên không còn đúng.

Hiệu năng chỉ là một chân trong ba chân. Đội quen ông nào, hệ sinh thái công cụ ra sao, chi phí vận hành thế nào, cả ba đều nặng ngang hiệu năng khi quyết định thật. Tôi có chia sẻ thêm trong bài Tối ưu SQL nên bắt đầu từ đâu.

Làm được gì trong 7 ngày tới?

  1. Chạy câu số 4 và số 7, đếm xem bảng nóng nhất đeo bao nhiêu index.
  2. Chạy câu số 2, xem tỷ lệ HOT trên bảng đó.
  3. Với PostgreSQL, chạy câu số 3, tìm bảng có n_dead_tup cao bất thường.
  4. Lấy câu báo cáo chậm nhất, chạy explain analyze, xem nó dùng kiểu join nào.
  5. Bỏ index không câu lệnh nào dùng tới. Việc rẻ nhất mà cho kết quả nhanh nhất.
  6. Đang chạy MySQL 5.7 thì xếp lịch nâng lên 8.0.

Cứ làm đi. Sai lại sửa.

Câu hỏi hay gặp

PostgreSQL có phải chậm hơn MySQL không?

Không. PostgreSQL chậm hơn ở đúng một hoàn cảnh: ghi nhiều trên bảng đeo nhiều secondary index. Ở câu lệnh phân tích phức tạp thì ngược lại, nhờ bộ tối ưu tốt hơn. Hỏi ông nào nhanh hơn mà không nói hoàn cảnh thì không có câu trả lời.

Vì sao Uber bỏ PostgreSQL sang MySQL?

Vì tải của họ nặng về ghi và bảng có rất nhiều index. Mỗi lần sửa một cột, PostgreSQL phải cập nhật toàn bộ index vì index trỏ vào vị trí vật lý của dòng. Đây là bài toán riêng của họ, không phải kết luận chung.

Vacuum của PostgreSQL và purge của MySQL khác nhau chỗ nào?

Khác ở chỗ dọn. Vacuum dọn ngay trên bảng đang phục vụ người dùng, nên nó ảnh hưởng tới các phiên đang làm việc với bảng đó. Purge của MySQL dọn trên vùng undo, tách khỏi bảng chính, nên nhẹ hơn.

Nâng MySQL 5.7 lên 8.0 thì câu lệnh có tự nhanh hơn không?

Có khả năng, lý do là bộ tối ưu được nâng chứ không phải máy khỏe lên. MySQL 8 có hash join từ 8.0.18 và cách tính cost cũng khác. Đừng coi là phép màu, vẫn phải đo lại từng câu lệnh sau khi nâng.

HOT trong PostgreSQL có chữa được khuếch đại ghi không?

Chữa được, nhưng chỉ khi câu update không đụng cột nào đang được index và trang còn đủ chỗ. Hệ thống hay update đúng cột có index thì HOT không giúp được. Kiểm bằng cột n_tup_hot_upd trong pg_stat_user_tables.

Câu lệnh của tôi đơn giản thì nên chọn ông nào?

Ông nào cũng được. Câu lệnh đơn giản, dữ liệu nhỏ thì hai ông cho kết quả gần như nhau. Lúc đó chọn theo thứ đội quen tay, theo hệ sinh thái công cụ và chi phí vận hành.

Đúc kết

Chuyện chọn PostgreSQL hay MySQL không nằm ở bảng so sánh tính năng. Nó nằm ở hai chỗ trong kiến trúc: cách hai ông làm MVCC, và cách bộ tối ưu dựng chiến lược thực thi.

Ghi nhiều, nhiều index, người dùng đồng thời lớn thì nghiêng về MySQL. Báo cáo nặng, câu lệnh phức tạp thì nghiêng về PostgreSQL. Hiểu cái gốc rồi thì lần sau gặp một loại database mới, anh em cũng tự đánh giá được, không phải đi hỏi ai.

Anh em muốn đi sâu hơn vào tối ưu cơ sở dữ liệu và làm qua nhiều bài toán thật thì tham gia chương trình của tôi. Tùy anh em.

Nguồn tham khảo