ducdev
Backend / Bài viết

PostgreSQL Performance — 7 Kỹ Thuật Tối Ưu Query Bạn Cần Biết

Query chậm là kẻ thù số một của ứng dụng web. Bài viết này chia sẻ 7 kỹ thuật tối ưu PostgreSQL thực chiến, từ index đúng chỗ đến EXPLAIN ANALYZE.

a
admin
11/01/2026 · 3 phút đọc · 0 lượt xem
Chia sẻ

Ứng dụng của bạn đang chạy chậm? Trong 80% trường hợp, thủ phạm là database query. Không phải do PostgreSQL không đủ mạnh — mà do chúng ta chưa dùng đúng cách.

1. EXPLAIN ANALYZE — Bắt Đầu Từ Đây

Trước khi tối ưu bất cứ thứ gì, hãy đo lường. EXPLAIN ANALYZE cho bạn biết PostgreSQL thực sự làm gì:

EXPLAIN ANALYZE
SELECT p.title, u.username
FROM posts p
JOIN auth_user u ON p.author_id = u.id
WHERE p.status = 'published'
ORDER BY p.published_at DESC
LIMIT 20;

Tìm kiếm những điểm đỏ: Seq Scan trên bảng lớn, cost cao, rows estimate sai xa thực tế.

2. Index Đúng Chỗ

Index là công cụ mạnh nhất nhưng cũng dễ dùng sai nhất:

-- Index cho cột thường dùng trong WHERE
CREATE INDEX idx_posts_status ON posts(status);

-- Composite index theo thứ tự filter/sort
CREATE INDEX idx_posts_status_date
ON posts(status, published_at DESC);

-- Index cho foreign key (Django không tự tạo!)
CREATE INDEX idx_posts_author ON posts(author_id);

Lưu ý: Index không phải là miễn phí — chúng chiếm disk space và làm chậm INSERT/UPDATE. Chỉ tạo index cho những cột thực sự cần.

3. Tránh N+1 Queries

Đây là vấn đề phổ biến nhất với ORM. Trong Django:

# Xấu — N+1: 1 query lấy posts + N query cho mỗi author
posts = Post.objects.filter(status='published')
for post in posts:
    print(post.author.username)  # Query riêng mỗi lần!

# Tốt — 1 query với JOIN
posts = Post.objects.filter(status='published').select_related('author')

# Cho many-to-many (tags)
posts = Post.objects.prefetch_related('tags')

4. Partial Indexes

Khi chỉ query một subset của data, partial index nhỏ hơn và nhanh hơn:

-- Chỉ index bài published
CREATE INDEX idx_published_posts
ON posts(published_at DESC)
WHERE status = 'published';

-- Query này sẽ dùng index trên
SELECT * FROM posts
WHERE status = 'published'
ORDER BY published_at DESC;

5. Connection Pooling

Mỗi connection PostgreSQL tốn ~5MB RAM. Dùng PgBouncer hoặc Django database pooling để tái sử dụng connections:

# Django settings với pgbouncer
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'CONN_MAX_AGE': 600,  # Giữ connection 10 phút
        # ... other settings
    }
}

6. Tránh SELECT *

# Xấu — lấy tất cả columns kể cả content (có thể MB)
posts = Post.objects.all()

# Tốt — chỉ lấy những gì cần
posts = Post.objects.values('id', 'title', 'slug', 'published_at')

7. Vacuum Và Statistics

PostgreSQL cần được "dọn dẹp" định kỳ. Trong production, đảm bảo autovacuum đang chạy và cập nhật statistics thường xuyên:

-- Cập nhật statistics để query planner chính xác hơn
ANALYZE posts;

-- Xem bảng nào cần vacuum
SELECT relname, n_dead_tup, n_live_tup
FROM pg_stat_user_tables
ORDER BY n_dead_tup DESC;
Đừng tối ưu premature. Đo lường trước, tối ưu sau — và luôn verify kết quả bằng benchmark thực tế.

Kết Luận

PostgreSQL cực kỳ mạnh mẽ khi được dùng đúng cách. Bắt đầu với EXPLAIN ANALYZE để tìm bottleneck thực sự, sau đó áp dụng từng kỹ thuật một cách có đo lường. Performance optimization là quá trình lặp đi lặp lại, không phải một lần là xong.

#PostgreSQL #database #Performance #SQL
a
Tác giả
admin

Lập trình viên, yêu thích chia sẻ kiến thức về công nghệ và phát triển phần mềm.

Bình luận

Chưa có bình luận. Hãy là người đầu tiên!

Để lại bình luận

Bình luận sẽ được duyệt trước khi hiển thị.