Quay lại danh sách
Tin tức công nghệ

Tối ưu hóa PostgreSQL cho ứng dụng RAG: Cách cấu hình pgvector để truy vấn hàng triệu Vector dưới 10ms

4 tháng 6, 2026

Giới thiệu: Thách thức mở rộng quy mô Vector Search trong ứng dụng RAG

Trong kỷ nguyên bùng nổ của trí tuệ nhân tạo (AI) và các mô hình ngôn ngữ lớn (LLM), Retrieval-Augmented Generation (RAG) đã trở thành kiến trúc chuẩn mực để giải quyết bài toán giới hạn tri thức và hiện tượng "ảo tưởng" (hallucination) của mô hình. Trọng tâm của mọi hệ thống RAG là Vector Database – nơi lưu trữ và thực hiện tìm kiếm ngữ nghĩa (semantic search) dựa trên các chuỗi embedding vector.

Khi bắt đầu triển khai dự án, PostgreSQL cùng tiện ích mở rộng (extension) pgvector luôn là lựa chọn hàng đầu của các kỹ sư nhờ vào tính ổn định, hệ sinh thái phong phú và khả năng tích hợp dữ liệu quan hệ sẵn có. Tuy nhiên, khi hệ thống tăng trưởng từ vài nghìn lên hàng triệu vector, hiệu năng truy vấn thường giảm sút nghiêm trọng nếu không được cấu hình đúng cách. Độ trễ (latency) tăng cao vượt mức 100ms sẽ trực tiếp phá hủy trải nghiệm người dùng trong các ứng dụng thời gian thực.

Bài viết này sẽ hướng dẫn bạn từng bước tối ưu hóa PostgreSQL và pgvector một cách chuyên sâu, giúp hệ thống đạt tốc độ truy vấn dưới 10ms ngay cả khi đối mặt với cơ sở dữ liệu hàng triệu dòng.

---

1. Lựa chọn Index phù hợp: IVFFlat vs HNSW

Để tìm kiếm nhanh chóng trong không gian vector khổng lồ, việc xây dựng chỉ mục (index) là bắt buộc. Trong pgvector, hai loại chỉ mục phổ biến nhất là IVFFlat (Inverted File with Flat Compression) và HNSW (Hierarchical Navigable Small World).

Quy tắc cốt lõi: Đối với các ứng dụng RAG quy mô doanh nghiệp yêu cầu độ trễ cực thấp và độ chính xác cao, HNSW là sự lựa chọn không thể thay thế.

So sánh chi tiết giữa IVFFlat và HNSW:

  • IVFFlat: Thời gian xây dựng index nhanh hơn, tốn ít bộ nhớ RAM hơn. Tuy nhiên, hiệu năng truy vấn (recall/latency trade-off) giảm mạnh khi dữ liệu tăng và yêu cầu phải build lại index thường xuyên khi dữ liệu thay đổi.
  • HNSW: Tốc độ truy vấn vượt trội (đạt mức vài mili-giây), độ chính xác (recall rate) cực cao lên đến 95-99%. Điểm hạn chế duy nhất là tốn nhiều tài nguyên bộ nhớ RAM và thời gian khởi tạo lâu hơn.

Để đạt mục tiêu dưới 10ms cho hàng triệu vector, chúng ta sẽ tập trung hoàn toàn vào việc tối ưu cấu trúc chỉ mục HNSW.

---

2. Kỹ thuật cấu hình tham số HNSW tối ưu

Khi khởi tạo index HNSW, hai tham số quyết định trực tiếp đến sự cân bằng giữa tốc độ xây dựng, dung lượng bộ nhớ và hiệu năng truy vấn là m và ef_construction. Cú pháp khởi tạo chuẩn xác như sau:

CREATE INDEX ON items USING hnsw (embedding vector_cosine_ops)
WITH (m = 16, ef_construction = 64);

Hãy cùng phân tích sâu về ý nghĩa và cách tinh chỉnh các tham số này:

Tham số m (Max Connections)

Đây là số lượng liên kết tối đa của mỗi phần tử vector với các phần tử lân cận trong mỗi tầng của đồ thị. Giá trị mặc định thường là 16. Đối với các ứng dụng RAG thông thường (vector từ 768 đến 1536 chiều như OpenAI text-embedding-3), giá trị từ 16 đến 32 là tối ưu. Tăng m giúp tăng độ chính xác ở các không gian nhiều chiều nhưng làm tăng kích thước index trên RAM.

Tham số ef_construction

Tham số này quyết định số lượng phần tử lân cận được kiểm tra trong quá trình xây dựng index. Giá trị càng lớn, đồ thị càng chính xác nhưng thời gian build index càng lâu. Bạn nên đặt giá trị này tối thiểu là 64 hoặc 128 cho môi trường production.

Tham số ef_search (Cấu hình khi truy vấn)

Đây là vũ khí bí mật giúp bạn kiểm soát trực tiếp độ trễ khi runtime. Khác với hai tham số trên, ef_search có thể cấu hình linh hoạt theo từng phiên làm việc (session):

SET hnsw.ef_search = 20;

Giảm giá trị ef_search (xuống 16 hoặc 20) giúp giảm số bước duyệt đồ thị, đẩy độ trễ xuống dưới 5ms nhưng có thể làm giảm nhẹ độ chính xác (recall). Ngược lại, tăng ef_search sẽ tăng độ chính xác nhưng làm tăng thời gian phản hồi. Bạn cần thực hiện benchmark trên tập dữ liệu thực tế để tìm ra điểm cân bằng.

---

3. Cấu hình phần cứng và phân bổ bộ nhớ PostgreSQL

Chỉ mục HNSW hoạt động hiệu quả nhất khi toàn bộ index nằm trọn trong bộ nhớ RAM (In-Memory). Nếu PostgreSQL phải đọc dữ liệu index từ đĩa cứng (ngay cả ổ SSD NVMe), hiệu năng sẽ giảm sút hàng trăm lần.

Hãy điều chỉnh các tham số trong file cấu hình postgresql.conf dựa trên tài nguyên máy chủ của bạn:

  1. shared_buffers: Đặt khoảng 25% đến 40% tổng dung lượng RAM của hệ thống. Đây là vùng nhớ đệm để PostgreSQL lưu trữ các trang dữ liệu và index thường xuyên truy cập.
  2. maintenance_work_mem: Cần được cấp phát lớn (ví dụ: 2GB đến 4GB) trước khi chạy lệnh CREATE INDEX. HNSW yêu cầu rất nhiều RAM trong quá trình dựng đồ thị. Thất bại trong việc cấp phát đủ bộ nhớ này sẽ khiến tiến trình bị ghi xuống đĩa, kéo dài thời gian build hàng tiếng đồng hồ.
  3. effective_cache_size: Đặt khoảng 50% đến 75% tổng RAM nhằm giúp bộ tối ưu hóa truy vấn (Query Planner) nhận biết chính xác lượng bộ nhớ có sẵn cho việc lưu bộ đệm.
---

4. Chiến lược nâng cao: Phân mảnh dữ liệu (Partitioning) và Kết hợp lọc thuộc tính

Khi quy mô vector vượt qua ngưỡng 10 triệu, việc duy trì một đồ thị HNSW duy nhất sẽ trở nên quá tải. Lúc này, bạn cần áp dụng các chiến lược kiến trúc nâng cao.

Phân mảnh dữ liệu (Table Partitioning)

Trong hệ thống RAG, người dùng thường chỉ truy vấn dữ liệu thuộc một phân vùng nhất định (ví dụ: theo khách hàng - Tenant ID, theo năm tài chính, hoặc theo danh mục tài liệu). Sử dụng tính năng Declarative Partitioning của PostgreSQL để chia nhỏ bảng vector:

CREATE TABLE documents (
    id uuid,
    tenant_id text,
    embedding vector(1536),
    content text
) PARTITION BY LIST (tenant_id);

Bằng cách này, mỗi truy vấn sẽ chỉ kích hoạt một index HNSW nhỏ của riêng phân vùng đó, giúp thu hẹp phạm vi tìm kiếm và đảm bảo thời gian phản hồi luôn ở mức cực thấp.

Tối ưu hóa truy vấn hỗn hợp (Hybrid Search và Lọc Metadata)

Một lỗi phổ biến là thực hiện lọc dữ liệu metadata sau khi đã tìm kiếm vector (Post-filtering), dẫn đến việc mất dấu các kết quả phù hợp nhất. Để pgvector tối ưu tốt nhất, hãy tận dụng Iterative Index Scan bằng cách kết hợp index của thuộc tính thường dùng (như B-Tree index cho cột trạng thái hoặc ngày tháng) cùng với HNSW index. PostgreSQL sẽ tự động tính toán để đưa ra lộ trình quét tối ưu nhất.

---

Kết luận và Khuyến nghị cho Production

Tối ưu hóa PostgreSQL cho ứng dụng RAG không phải là một công việc cấu hình một lần rồi bỏ đấy, mà là một quá trình liên tục thử nghiệm và đánh giá. Để duy trì cam kết độ trễ < 10ms trên quy mô lớn, hãy tuân thủ bộ quy tắc cốt lõi sau:

  • Luôn ưu tiên sử dụng HNSW Index cho các chiều vector lớn và tần suất đọc cao.
  • Giám sát tỷ lệ trúng bộ đệm (Cache Hit Ratio) của Index, đảm bảo RAM luôn đủ lớn để chứa toàn bộ đồ thị HNSW.
  • Tinh chỉnh linh hoạt tham số hnsw.ef_search để đạt được tốc độ mong muốn tùy theo kịch bản kinh doanh.
  • Áp dụng phân mảnh bảng dữ liệu ngay từ đầu nếu dự báo quy mô sẽ vượt ngưỡng hàng chục triệu vector.

PostgreSQL với pgvector hoàn toàn đủ mạnh mẽ để cân các tác vụ AI của doanh nghiệp, giúp bạn tiết kiệm chi phí vận hành và giảm bớt độ phức tạp trong kiến trúc hệ thống so với việc phải duy trì một database vector độc lập.