Sau chuỗi bài về lưu trữ và bảo trì, ta chuyển sang cấu hình bộ nhớ — và tham số đầu tiên, quan trọng nhất, là shared_buffers. Đây là bộ nhớ đệm chính của PostgreSQL: nơi nó giữ các trang bảng và index trong RAM để không phải đọc lại từ đĩa. Mặc định 128MB thường quá nhỏ cho production, nhưng cám dỗ "đặt thật lớn" cũng sai — vì một lý do đặc thù của PostgreSQL: double buffering với bộ đệm của hệ điều hành. Bài này đo thật cách shared_buffers hoạt động và cho quy tắc đặt đúng.
shared_buffers là gì
shared_buffers là vùng RAM chung mà PostgreSQL dùng làm bộ đệm cho các trang 8KB của bảng và index. Đọc một trang đã có trong shared_buffers là cache hit (nhanh, từ RAM); không có thì phải đọc từ đĩa (hoặc OS cache).
SHOW shared_buffers; -- mặc định 128MB (thường quá nhỏ)
SHOW effective_cache_size; -- 4GB — chỉ là GỢI Ý cho planner, không cấp phát
Với 128MB, shared_buffers chứa được 128MB / 8KB = 16.384 trang. Đo thật container này: chỉ 478 buffer đang dùng, phần lớn là các bảng catalog hệ thống (pg_attribute, pg_statistic...).

Hình 1: shared_buffers là bộ đệm chính giữ trang trong RAM. Cạm bẫy là double buffering với OS cache — đặt quá lớn phí RAM. Quy tắc ~25% RAM; theo dõi bằng cache hit ratio và pg_buffercache.
Đo thật: bảng lớn hơn shared_buffers
Bảng pgbench_accounts là 648 MB — lớn hơn nhiều so với shared_buffers 128MB, nên nó không thể nằm hết trong bộ đệm:

Hình 2: shared_buffers 128MB chứa 16.384 trang (chỉ 478 đang dùng). pgbench_accounts 648 MB lớn hơn SB nên cache hit trong SB chỉ 37,53%. Nhưng tập nóng ở lại: quét subset lần 1 read=1458, lần 2 read=0.
- Cache hit trong SB của
pgbench_accounts: chỉ 37,53% — vì bảng lớn hơn shared_buffers, phần lớn dữ liệu phải đọc từ OS cache/đĩa. Cache hit toàn cục 92,53% (OLTP tốt nên đạt >99%). - Nhưng tập nóng ở lại SB: quét một subset nhỏ (
aid<100.000) lần đầu đọcread=1458từ đĩa; lần thứ hairead=0— subset đó giờ nằm hoàn toàn trong shared_buffers. Đây là điều quan trọng: shared_buffers không cần chứa cả dữ liệu, chỉ cần chứa tập nóng hay được truy cập.
Cạm bẫy: double buffering — vì sao không đặt quá lớn
Đây là điểm đặc thù của PostgreSQL. Dữ liệu của PostgreSQL được cache ở hai nơi cùng lúc: shared_buffers (bộ đệm của PostgreSQL) và OS page cache (bộ đệm của hệ điều hành). Khi bạn đặt shared_buffers quá lớn:
- Cùng một trang có thể bị cache hai lần (trong SB và trong OS cache) — lãng phí RAM.
- RAM lấy cho SB là RAM không còn cho OS cache,
work_mem(bộ nhớ sort/hash — bài sau), và các kết nối.
Vì vậy quy tắc phổ biến là ~25% RAM cho shared_buffers, không hơn — để OS cache dùng phần còn lại hiệu quả. Đặt SB 80% RAM thường chậm hơn SB 25% vì mất double buffering và bỏ đói các thành phần khác.
effective_cache_size: chỉ là gợi ý cho planner
Đừng nhầm effective_cache_size (4GB ở đây) với một cấp phát bộ nhớ — nó không cấp phát gì cả. Nó chỉ nói cho planner biết tổng bộ nhớ cache khả dụng (shared_buffers + ước lượng OS cache), để planner quyết định index scan có lợi hơn seq scan không (nếu dữ liệu có thể trong cache thì index scan rẻ hơn). Đặt nó khoảng 50-75% RAM — cao hơn shared_buffers vì nó tính cả OS cache.
Đánh đổi cần cân nhắc
| RAM máy chủ | shared_buffers (~25%) | effective_cache_size (~50-75%) |
|---|---|---|
| 8 GB | ~2 GB | 4-6 GB |
| 32 GB | ~8 GB | 16-24 GB |
25% là điểm khởi đầu, không phải luật. Với workload đọc-nặng và tập dữ liệu nóng vừa RAM, tăng SB cao hơn (40%) có thể tốt. Với máy chủ chia sẻ nhiều dịch vụ, hạ thấp hơn. Đo cache hit ratio thật và điều chỉnh — đừng copy một con số mù quáng.
Đổi shared_buffers cần khởi động lại. Khác nhiều tham số reload được, shared_buffers là bộ nhớ chung cấp phát lúc khởi động — đổi nó phải ALTER SYSTEM SET shared_buffers rồi restart PostgreSQL. Lên kế hoạch cho downtime ngắn.
Trên container/cloud, RAM khả dụng có thể khác RAM máy. Trong Docker (như lab này), giới hạn RAM của container mới là con số để tính 25%, không phải RAM máy chủ vật lý. Trên dịch vụ quản lý, thường nhà cung cấp đã đặt sẵn shared_buffers theo instance size — kiểm trước khi chỉnh.
Ba ý mang về
- shared_buffers là bộ đệm chính của PostgreSQL, mặc định 128MB thường quá nhỏ: nó chỉ cần chứa tập dữ liệu nóng, không cần cả bảng — đo thật, subset hay truy cập ở lại SB (read 1458 → 0 ở lần đọc thứ hai) dù bảng 648 MB lớn hơn SB.
- Quy tắc ~25% RAM, không hơn, vì double buffering: dữ liệu PG được cache ở cả shared_buffers lẫn OS page cache — đặt SB quá lớn phí RAM lẽ ra để cho OS cache,
work_mem, và kết nối. - effective_cache_size chỉ là gợi ý cho planner (~50-75% RAM), không cấp phát: theo dõi cache hit ratio (OLTP nên >99%) và
pg_buffercacheđể biết SB đủ chưa; đổi shared_buffers cần restart.
Phần sau ta xét tham số bộ nhớ quan trọng thứ hai, cấp phát theo từng truy vấn: Phần sau mổ xẻ work_mem — RAM cho sort và hash, vì sao đặt sai gây tràn đĩa hoặc hết bộ nhớ, và cách tính an toàn theo số kết nối.