PostgreSQL Performance Tuning Production
PostgreSQL Performance Tuning คืออะไร?
PostgreSQL เป็น database ที่ทรงพลังที่สุดในโลก open-source แต่ default config ถูกตั้งมาให้ทำงานบนเครื่องที่มี RAM แค่ 1-2 GB ดังนั้น ถ้าใช้ PostgreSQL ใน production โดยไม่ tune ก็เหมือนขับ Ferrari ด้วยเกียร์ 1 ตลอดทาง
บทความนี้จะสอนวิธี tune PostgreSQL ให้เร็วขึ้น 5-20 เท่าสำหรับ server ที่มี RAM 16 GB ขึ้นไป
postgresql.conf — ค่าสำคัญที่ต้อง Tune
| Parameter | Default | แนะนำ (RAM 32GB) | คำอธิบาย |
|---|---|---|---|
| shared_buffers | 128 MB | 8 GB (25% RAM) | Buffer pool สำหรับ cache data pages |
| effective_cache_size | 4 GB | 24 GB (75% RAM) | บอก planner ว่ามี cache เท่าไหร่ |
| work_mem | 4 MB | 64-256 MB | Memory per sort/hash operation |
| maintenance_work_mem | 64 MB | 2 GB | Memory สำหรับ VACUUM, CREATE INDEX |
| max_connections | 100 | 200 | ใช้ PgBouncer แทนการเพิ่ม |
| wal_buffers | -1 | 64 MB | Buffer สำหรับ WAL writes |
| random_page_cost | 4.0 | 1.1 | ลดลงถ้าใช้ SSD (สำคัญมาก!) |
| effective_io_concurrency | 1 | 200 | เพิ่มสำหรับ SSD/NVMe |
ตัวอย่าง Config สำหรับ Server RAM 32 GB
# /etc/postgresql/16/main/postgresql.conf
# Memory
shared_buffers = '8GB'
effective_cache_size = '24GB'
work_mem = '128MB'
maintenance_work_mem = '2GB'
wal_buffers = '64MB'
# Disk / SSD optimization
random_page_cost = 1.1
effective_io_concurrency = 200
max_parallel_workers_per_gather = 4
max_parallel_workers = 8
# WAL / Checkpoints
wal_level = replica
max_wal_size = '4GB'
min_wal_size = '1GB'
checkpoint_completion_target = 0.9
# Connections (ใช้ PgBouncer แทน)
max_connections = 200
# Logging
log_min_duration_statement = 500 # log queries ที่นานกว่า 500ms
log_checkpoints = on
log_lock_waits = on
Index Optimization — หัวใจของ Performance
Index ที่ดีทำให้ query เร็วขึ้น 100-1000 เท่าข้อแนะนำ:
- ดู slow queries ก่อน — เปิด
pg_stat_statementsextension แล้วดู query ที่ช้าที่สุด - ใช้ EXPLAIN ANALYZE —
EXPLAIN (ANALYZE, BUFFERS) SELECT ...ดูว่า query ใช้ Seq Scan หรือ Index Scan - สร้าง Partial Index —
CREATE INDEX ON orders (status) WHERE status = 'pending'ถ้า query filter ค่าเดิมซ้ำๆ - ใช้ Covering Index —
CREATE INDEX ON users (email) INCLUDE (name, role)ลด table lookup - หา Missing Indexes — ดูจาก
pg_stat_user_tablesถ้า seq_scan สูงมากแสดงว่าขาด index
Connection Pooling ด้วย PgBouncer
PostgreSQL สร้าง process ใหม่ทุก connection ใช้ RAM ~10 MB ต่อ connection ถ้ามี 500 connections = 5 GB RAM เฉพาะ connections PgBouncer แก้ปัญหานี้โดย pool connections ให้ reuse
# /etc/pgbouncer/pgbouncer.ini
[databases]
mydb = host=127.0.0.1 port=5432 dbname=mydb
[pgbouncer]
listen_addr = 0.0.0.0
listen_port = 6432
pool_mode = transaction # แนะนำ transaction mode
max_client_conn = 1000
default_pool_size = 50
min_pool_size = 10
ผลลัพธ์: app เชื่อมต่อ PgBouncer port 6432 แทน PostgreSQL port 5432 โดย PgBouncer จะ pool 1000 client connections ผ่าน 50 PostgreSQL connections จริงลด memory usage ได้มหาศาล
VACUUM และ Maintenance
PostgreSQL ใช้ MVCC ที่สร้าง dead tuples ทุกครั้งที่ UPDATE/DELETE ถ้าไม่ VACUUM ตารางจะบวมขึ้นเรื่อยๆ:
- autovacuum — เปิดเสมอ (default on) อย่าปิด
- ตั้ง autovacuum ให้ aggressive ขึ้น สำหรับตารางที่ update บ่อย
- pg_repack — ใช้ repack table ที่บวมมากโดยไม่ต้อง lock table
- ตรวจสอบ bloat —
SELECT relname, n_dead_tup FROM pg_stat_user_tables ORDER BY n_dead_tup DESC;
Q: PostgreSQL vs MySQL ใน production ตัวไหนดีกว่า?
ขึ้นอยู่กับ use case ครับ PostgreSQL ดีกว่าสำหรับ complex queries, JSON, geospatial, full-text search และ data integrity MySQL ดีกว่าสำหรับ simple read-heavy workloads และ replication ง่ายกว่าในปี 2026 PostgreSQL ได้รับความนิยมมากกว่าแล้ว