Dùng AI đọc EXPLAIN để khoanh vùng truy vấn PostgreSQL chậm
EXPLAIN cho thấy PostgreSQL dự định đọc và xử lý dữ liệu thế nào. Dùng AI để diễn giải plan, nhận diện Seq Scan, Filter và ước lượng số dòng — nhưng luôn xác minh lại bằng SQL, schema và môi trường thực tế.
Dashboard chậm, refresh báo cáo kéo dài, truy vấn trong công cụ BI chạy mãi chưa xong: phản xạ thường thấy là “thêm index”. Nhưng trước khi sửa SQL hay thay đổi hệ thống, cần trả lời một câu cơ bản hơn: PostgreSQL đang dự định đọc dữ liệu theo cách nào?
EXPLAIN cho bạn xem query plan mà PostgreSQL planner chọn. AI có thể hỗ trợ diễn giải plan nhanh, biến các node kỹ thuật thành câu hỏi dễ kiểm tra hơn. Tuy nhiên, AI không thay thế việc đối chiếu với câu SQL, schema và dữ liệu thực tế.
EXPLAIN cho bạn thấy gì?
PostgreSQL tạo một query plan cho mỗi truy vấn. Plan có cấu trúc dạng cây:
Các node ở phía dưới thường đọc dữ liệu gốc từ bảng.
Các node phía trên có thể thực hiện JOIN, tổng hợp, sắp xếp hoặc các thao tác khác.
Mỗi node thể hiện một phần công việc mà planner dự tính thực hiện.
Ví dụ trong tài liệu PostgreSQL:
sql
EXPLAIN SELECT FROM tenk1;
Kết quả có dạng:
text
Seq Scan on tenk1 (cost=0.00..445.00 rows=10000 width=244)
Đây là Seq Scan: PostgreSQL quét tuần tự bảng tenk1. Vì truy vấn không có WHERE, hệ thống phải đọc toàn bộ các dòng trong bảng.
Điều đó không tự động có nghĩa là plan tệ. Nếu báo cáo thực sự cần phần lớn hoặc toàn bộ dữ liệu, quét tuần tự có thể là lựa chọn phù hợp.
Cách đọc một dòng plan
Một node trong output EXPLAIN thường chứa các phần sau:
| Thành phần | Ý nghĩa |
|---|---|
| Seq Scan | Loại node; ở đây là quét tuần tự bảng |
| cost=0.00..445.00 | Chi phí khởi đầu và tổng chi phí ước lượng |
| rows=10000 | Số dòng node được ước lượng sẽ xuất ra |
| width=244 | Độ rộng trung bình của mỗi dòng đầu ra, tính bằng byte |
Có hai điểm rất dễ nhầm:
cost không phải số giây. Đây là đơn vị chi phí nội bộ do planner sử dụng để so sánh các plan.
rows không phải lúc nào cũng là số dòng node đã đọc. Đó là số dòng node dự kiến xuất ra. Một node có thể phải đọc nhiều dòng hơn rồi lọc bớt.
Ngoài ra, tổng chi phí của node cấp trên đã bao gồm chi phí của các node con. PostgreSQL chọn plan với mục tiêu tối thiểu hóa tổng chi phí ước lượng này.
Filter không đồng nghĩa với việc đọc ít dữ liệu
Hãy xem truy vấn có điều kiện lọc:
sql
EXPLAIN SELECT FROM tenk1 WHERE unique1 < 7000;
Ví dụ trong tài liệu cho kết quả:
text
Seq Scan on tenk1 (cost=0.00..470.00 rows=7000 width=244)
Filter: (unique1 < 7000)
Filter gắn với Seq Scan cho biết node quét tuần tự kiểm tra điều kiện unique1 < 7000 trên các dòng nó đọc, rồi chỉ xuất những dòng thỏa điều kiện.
Trong ví dụ này:
Planner vẫn phải đi qua toàn bộ bảng.
Số dòng đầu ra được ước lượng giảm xuống còn 7000.
Chi phí tổng không giảm, vì việc quét bảng vẫn diễn ra; kiểm tra điều kiện còn tạo thêm chi phí CPU.
Đây là điểm hữu ích khi đọc truy vấn phục vụ dashboard: một điều kiện WHERE có thể tồn tại, nhưng chưa chắc đã giúp giảm đáng kể lượng dữ liệu cần đọc.
Khi điều kiện thay đổi, plan cũng có thể đổi
Tài liệu PostgreSQL minh họa rằng với điều kiện chặt hơn:
sql
EXPLAIN SELECT FROM tenk1 WHERE unique1 < 100;
planner có thể chọn một kiểu node khác, chẳng hạn Bitmap Heap Scan.
Bài học không phải là “điều kiện chặt hơn luôn tốt hơn”, mà là: planner có thể chọn chiến lược đọc khác nhau tùy cấu trúc truy vấn và đặc điểm dữ liệu. Vì vậy, đừng chỉ nhìn câu SQL; hãy xem plan thực tế mà PostgreSQL tạo ra.
Dùng AI để đọc EXPLAIN: hỏi đúng, kiểm tra đúng
AI hữu ích nhất khi được giao vai trò diễn giải và lập danh sách kiểm tra, thay vì tự động quyết định cách tối ưu.
Bạn có thể đưa AI:
Câu SQL đã loại bỏ thông tin nhạy cảm.
Output EXPLAIN.
Schema tối giản: bảng, cột liên quan, kiểu dữ liệu và index hiện có.
Mục tiêu của báo cáo: tổng hợp, danh sách chi tiết, lọc theo khoảng thời gian hoặc phân nhóm.
Prompt mẫu:
text
Bạn là người review PostgreSQL query plan cho dashboard BI.
Hãy đọc EXPLAIN bên dưới và trả lời:
Các node đọc dữ liệu gốc là gì?
Có Seq Scan nào cần chú ý không? Giải thích dựa trên plan, không suy đoán.
rows tại mỗi node là số dòng đầu ra hay số dòng đã đọc?
Filter nào đang được áp dụng tại node scan?
Những thông tin nào còn thiếu trước khi đề xuất thay đổi SQL hoặc index?
Không được bịa tên bảng, cột hoặc index không xuất hiện trong input.
SQL:
<sql>
EXPLAIN:
<plan>
Schema và index hiện có:
<schema>
Một phản hồi tốt nên tách bạch ba phần:
Quan sát trực tiếp từ plan: có Seq Scan, có Filter, rows được ước lượng bao nhiêu.
Điều chưa thể kết luận: nguyên nhân khiến plan được chọn, mức độ chậm thực tế, hoặc thay đổi cụ thể cần áp dụng.
Thông tin cần kiểm tra thêm: cấu trúc bảng, index hiện có, khối lượng dữ liệu và yêu cầu của báo cáo.
Walkthrough: biến một plan thành checklist
Với plan:
text
Seq Scan on tenk1 (cost=0.00..470.00 rows=7000 width=244)
Filter: (unique1 < 7000)
AI có thể giúp diễn giải thành checklist sau:
| Quan sát từ plan | Việc cần kiểm tra |
|---|---|
| Có Seq Scan trên tenk1 | Bảng có đang là nguồn dữ liệu lớn trong workload báo cáo không? |
| Có Filter tại node scan | Điều kiện lọc có làm giảm đáng kể số dòng đầu ra không? |
| rows=7000 | Đây là ước lượng số dòng node xuất ra; cần đối chiếu với kết quả thực tế nếu cần |
| cost=0.00..470.00 | Không diễn giải con số này thành thời gian refresh hoặc SLA |
Tài liệu PostgreSQL cũng dùng relpages và reltuples trong pgclass để giải thích cách chi phí quét tuần tự được ước lượng:
sql
SELECT relpages, reltuples
FROM pgclass
WHERE relname = 'tenk1';
Trong ví dụ của tài liệu, chi phí Seq Scan được tính từ số trang đĩa cần đọc và số dòng cần xử lý, dựa trên các tham số chi phí của planner. Đây là cách hiểu cơ chế ước lượng, không phải phép đo thời gian chạy thực tế.
Vì sao không nên tin tuyệt đối vào một con số rows?
rows là ước lượng của planner, được xây dựng từ thống kê. PostgreSQL lưu ý rằng thống kê do ANALYZE tạo ra dựa trên mẫu ngẫu nhiên, không phải phép đếm chính xác.
Do đó:
Ước lượng có thể khác với số dòng thực tế.
Kết quả có thể thay đổi sau lần chạy ANALYZE.
Các ví dụ trong tài liệu có thể cho con số khác trên hệ thống của bạn.
Chi phí cũng phụ thuộc vào tham số chi phí của từng môi trường.
Đừng nhìn một giá trị rows rồi kết luận ngay planner đúng hoặc sai. Hãy xem đó là tín hiệu để kiểm tra thêm.
Checklist trước khi thay đổi truy vấn
[ ] Đã lưu câu SQL và output EXPLAIN hiện tại để so sánh.
[ ] Đã xác minh AI không bịa bảng, cột hoặc index.
[ ] Đã phân biệt cost ước lượng với thời gian người dùng chờ.
[ ] Đã hiểu rows là số dòng node ước lượng xuất ra.
[ ] Đã kiểm tra điều kiện Filter đang nằm ở node nào.
[ ] Đã đối chiếu plan với schema, dữ liệu và mục tiêu của dashboard.
[ ] Đã thử thay đổi trong môi trường phù hợp trước khi áp dụng rộng rãi.
AI giúp bạn đọc plan nhanh hơn và đặt câu hỏi có hệ thống hơn. Còn quyết định tối ưu tốt vẫn phải dựa trên điều PostgreSQL đang dự định làm, dữ liệu mà báo cáo thực sự cần, và các thông tin bạn đã kiểm chứng.