CodeGym /Các khóa học /SQL SELF /Theo dõi truy vấn chậm với pg_stat_statements

Theo dõi truy vấn chậm với pg_stat_statements

SQL SELF
Mức độ , Bài học
Có sẵn

pg_stat_statements là một extension tích hợp sẵn của PostgreSQL, cho phép bạn theo dõi xem thực sự có những truy vấn nào đang chạy trong database và chúng hoạt động ra sao. Nói đơn giản, nó giống như một trợ lý thầm lặng nhưng cực kỳ quan sát, ghi lại từng bước: truy vấn SQL nào đã chạy, mất bao lâu, chạy bao nhiêu lần và tải hệ thống như thế nào.

Tại sao cần cái này? Đầu tiên là để tìm ra truy vấn có vấn đề. Đôi khi database bị lag không phải vì một "kẻ xấu" nào đó, mà là do hàng chục truy vấn nặng giống nhau chạy quá thường xuyên. Thứ hai, thống kê giúp bạn thấy rõ truy vấn nào đang ngốn tài nguyên — CPU, RAM, ổ cứng. Bạn cũng có thể kiểm tra xem index có hoạt động như mong đợi không: có thể chỗ này không dùng index, chỗ khác lại thiếu index.

pg_stat_statements giúp bạn không phải đoán mò mà nhìn thấy số liệu thực — từ đó rút ra kết luận và tối ưu hóa.

Làm sao tìm truy vấn chậm?

Giờ mới là phần thú vị nè! Dùng bảng pg_stat_statements, mình có thể tìm các truy vấn chạy lâu hoặc gây tải nặng cho server.

Ý tưởng chính:

Mỗi dòng trong bảng pg_stat_statements là thống kê cho một truy vấn. Các truy vấn được nhóm theo text (trường query), và với mỗi truy vấn sẽ có các chỉ số sau:

  • total_time — tổng thời gian thực thi truy vấn, tính bằng mili giây.
  • calls — số lần truy vấn được thực thi.
  • mean_time — thời gian trung bình mỗi lần thực thi (total_time / calls).
  • rows — số dòng mà truy vấn trả về.

Ví dụ phân tích đơn giản

Thử tìm các truy vấn chậm nhất theo thời gian trung bình:

SELECT
    query,
    mean_time,
    calls,
    rows
FROM
    pg_stat_statements
ORDER BY
    mean_time DESC
LIMIT 5;

Truy vấn này sẽ trả về TOP 5 truy vấn chạy lâu nhất. Để ý trường mean_time: nếu giá trị ở đây vượt quá 500-1000 mili giây thì nên tối ưu lại truy vấn đó rồi nha.

Ví dụ phân tích truy vấn chậm

Cùng xem một ví dụ nhé:

Đây là kết quả khi chạy truy vấn trên:

query mean_time calls rows
SELECT * FROM orders WHERE status = 'new'; 1234.56 10 10000
SELECT * FROM products 755.12 5000 100
SELECT * FROM customers WHERE id = $1 543.21 1000 1

Chúng ta thấy gì?

Truy vấn bảng orders: chạy rất ít (chỉ 10 lần), nhưng mỗi lần lại kéo về tận 10 nghìn dòng. Có vẻ bảng này rất to và truy vấn không dùng index.

Truy vấn bảng products: gọi hàng triệu lần, chắc là trong vòng lặp của app. Mỗi lần chỉ trả về 100 dòng, nhưng do tần suất cao nên cũng thành vấn đề.

Truy vấn bảng customers: chạy khá nhanh (543 ms), nhưng lại bị gọi quá nhiều lần.

Tối ưu hóa truy vấn chậm

Khi đã tìm ra truy vấn có vấn đề, hãy xem execution plan bằng EXPLAIN ANALYZE. Ví dụ với truy vấn bảng orders:

EXPLAIN ANALYZE
SELECT * FROM orders WHERE status = 'new';

Có thể thấy gì?

Seq Scan: nếu truy vấn dùng quét tuần tự, hãy thêm index:

CREATE INDEX idx_orders_status ON orders (status);

Vấn đề lọc dữ liệu: nếu truy vấn kéo quá nhiều dòng, hãy xem lại câu truy vấn. Có thể cần thêm điều kiện hoặc giới hạn kết quả:

SELECT * FROM orders WHERE status = 'new' LIMIT 100;

Xuất thống kê theo thời gian thực thi

Đôi khi truy vấn có vấn đề không dễ nhận ra. Ví dụ, truy vấn thường gọi function hoặc subquery. Lúc này nên xem cột total_time:

SELECT
    query,
    total_time,
    calls,
    mean_time
FROM
    pg_stat_statements
ORDER BY
    total_time DESC
LIMIT 10;

Truy vấn này sẽ cho bạn thấy các truy vấn "đắt đỏ" nhất về tổng thời gian thực thi.

Tối ưu hóa index

Thường thì truy vấn chậm là do thiếu index cần thiết. Dùng pg_stat_statements để xem truy vấn nào không dùng index. Nếu bạn thấy nhiều truy vấn có filter giống nhau (ví dụ theo trường status), mà lại rất chậm, hãy thêm index phù hợp:

CREATE INDEX idx_orders_status ON orders (status);

Sau đó kiểm tra lại hiệu suất truy vấn với EXPLAIN ANALYZE.

Dùng pg_stat_statements, bạn có thể theo dõi hiệu suất truy vấn, tìm "nút thắt cổ chai" và cải thiện hiệu suất database của mình. Nhớ là càng phân tích truy vấn sớm thì tối ưu hệ thống càng dễ nha!

Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION