SQLite WAL Mode: Tăng tốc ghi và đọc đồng thời hiệu quả

SQLITE WAL MODE: Tăng tốc độ ghi và đọc đồng thời

SQLite WAL (Write-Ahead Logging) là chế độ ghi nhớ trước dùng thay thế rollback journal truyền thống. Khi bật WAL, mọi thay đổi được ghi vào một file WAL riêng biệt thay vì ghi trực tiếp vào file database chính. Điều này cho phép đọc và ghi chạy đồng thời — độc giả không block người ghi và ngược lại. Đây là tính năng giúp SQLite vượt xa hầu hết các hệ quản trình khác trong các tình huống đọc-ghi đồng thời.

WAL có từ phiên bản SQLite 3.7.0 (2010-07-21) và ngày nay là chế độ mặc định trong nhiều framework và công cụ vì độ ưu việt về hiệu năng. Bài viết tham khảo từ SQLite WAL documentationPRAGMA statements reference.

WAL hoạt động thế nào?

Đối với rollback journal truyền thống, SQLite ghi một bản sao của nội dung gốc vào file rollback journal, sau đó mới ghi thay đổi vào file database. Nếu rollback xảy ra, nội dung gốc được khôi phục. Quá trình này yêu cầu ghi hai lần — một lần vào journal và một lần vào database — làm giảm hiệu năng ghi.

Với WAL, cách tiếp cận đảo ngược: nội dung gốc được giữ nguyên trong file database, và các thay đổi được appended vào file WAL riêng. Commit xảy ra khi một bản ghi đặc biệt cho biết commit được ghi vào WAL — điều này có nghĩa là commit có thể thực hiện mà không cần ghi vào file database gốc, cho phép các độc giả tiếp tục đọc từ database gốc chưa bị thay đổi trong khi thay đổi đang được ghi vào WAL. Nhiều transaction có thể được append vào cuối cùng một file WAL duy nhất.

SQLite banner showing database performance

Checkpointing: chuyển WAL về database

Một checkpoint là thao tác chuyển nội dung từ file WAL trở lại file database. Có năm loại checkpoint:

  • PASSIVE — checkpoint càng nhiều frames có thể mà không chờ đợi bất kỳ reader hay writer nào. Đây là mặc định khi gọi wal_checkpoint không có đối số.
  • FULL — blocks writers nhưng cho phép readers chạy. Đảm bảo tất cả frames trong WAL đều được chuyển.
  • RESTART — giống FULL nhưng sau khi checkpoint xong, đảm bảo WAL bắt đầu lại từ đầu cho lần ghi kế tiếp.
  • TRUNCATE — giống RESTART nhưng cắt ngắn file WAL về 0 byte sau khi hoàn thành.
  • NOOP — không checkpoint bất kỳ frame nào, chỉ trả về thông tin thống kê.

Checkpoint tự động chạy khi WAL đạt 1000 trang (có thể thay đổi qua PRAGMA wal_autocheckpoint). Một checkpoint có thể chạy song song với readers, nhưng phải dừng nếu có reader đang đọc từ vùng cần ghi. Lập trình viên có thể tắt auto-checkpoint và chạy checkpoint trong thread riêng để tránh block thread chính.

PRAGMA WAL quan trọng

Bật WAL mode:

PRAGMA journal_mode = WAL;

Đặt ngưỡng tự động checkpoint (mặc định 1000 trang):

PRAGMA wal_autocheckpoint = 500;

Chạy checkpoint thủ công:

PRAGMA wal_checkpoint(FULL);

Lưu ý hiệu năng

Ghi nhanh hơn vì chỉ ghi một lần (thay vì hai lần như rollback journal), đồng thời I/O tuần tự hơn. Tuy nhiên, đọc sẽ chậm hơn khi file WAL lớn. Để duy trì hiệu năng đọc tốt, cần chạy checkpoint thường xuyên để giữ WAL nhỏ.

Với PRAGMA synchronous = NORMAL, checkpoint là thao tác duy nhất thực hiện fsync — nếu chạy trong thread riêng, thread chính sẽ không bao giờ block trên sync. Tuy nhiên, transactions sẽ không còn durable sau power failure. Nếu bạn cần durability, giữ synchronous = FULL.

Hạn chế của WAL

  • Không hoạt động trên filesystem mạng — tất cả process phải trên cùng một máy vì WAL sử dụng shared memory (-shm file).
  • Không thể thay đổi page_size sau khi bật WAL, kể cả với VACUUM hay restore.
  • File WAL và shm phụ trợ tăng kích thước ứng dụng — không phù hợp khi dùng SQLite làm application file format.
  • Đối với ứng dụng đọc nhiều, ghi ít, WAL có thể chậm hơn 1-2% so với rollback journal.

Terminal showing SQLite commands for WAL mode

Bảng so sánh journal_mode

Journal mode Đặc điểm Hiệu năng
DELETE Mặc định, xóa rollback journal sau mỗi transaction Chuẩn, an toàn
TRUNCATE Truncate journal về 0 byte thay vì delete Nhanh hơn DELETE trên một số filesystem
PERSIST Không xóa journal, chỉ ghi đầu với zeros Ít syscall hơn
MEMORY Lưu journal trong RAM Rất nhanh nhưng không an toàn
WAL Write-ahead log, đọc+ghi đồng thời Nhanh nhất với workload đọc+ghi đồng thời
OFF Tắt journal hoàn toàn Nhanh nhất nhưng rủng rỗng dữ liệu

Kết luận

WAL mode là lựa chọn tối ưu cho các ứng dụng có nhu cầu đọc-ghi đồng thời hoặc ghi nhiều. Kết hợp với PRAGMA synchronous = NORMAL và checkpoint trong thread riêng, bạn có thể đạt hiệu năng tối đa trong khi vẫn duy trì độ an toàn cần thiết.

Để bắt đầu, chạy PRAGMA journal_mode = WAL; và theo dõi dung lượng file -wal. Nếu đọc quá chậm, giảm wal_autocheckpoint. Nếu ghi quá chậm, thử synchronous = NORMAL. WAL là cải tiến lớn nhất của SQLite từ phiên bản 3.7.0, và là bắt buộc cho mọi ứng dụng production dùng SQLite với concurrent access.

Tôi là một lập trình viên IOS. Code chính là IOS nhưng thỉnnh thoảng vẫn đá sang Android hoặc web. Mặc dù không quá thông thạo nhưng tôi sẽ chia sẻ những kiến thức mà mình đã tìm hiểu, áp dụng qua.

Bài viết liên quan

SQLite FTS5 Full-Text Search: Tìm kiếm nội dung trong app không cần server

SQLite FTS5 (Full-Text Search version 5) là công cụ tìm kiếm toàn văn bản tích hợp sẵn trong SQLite, cho phép tìm kiếm nội dung văn bản nhanh chóng mà…

Xem thêm

Golang Concurrency Patterns: Worker Pool, Pipeline, Fan-out/Fan-in thực tế

Golang nổi tiếng với mô hình concurrency “share memory by communicating” thay vì “share memory by locking”. Nhưng pattern thông thường như worker pool, pipeline, fan-out/fan-in không tự động xuất…

Xem thêm

CI/CD GitHub Actions vs GitLab CI: Công cụ nào phù hợp dự án 2025?

CI/CD GitHub Actions vs GitLab CI: Công cụ nào phù hợp dự án 2025? CI/CD (Continuous Integration / Continuous Deployment) là xương sống của DevOps hiện đại — tự động…

Xem thêm
0 0 đánh giá
Article Rating
Theo dõi
Thông báo của
guest
0 Comments
Cũ nhất
Mới nhất Được bỏ phiếu nhiều nhất