TL;DR - Cách khắc phục nhanh
Nếu bạn cần chạy một truy vấn tốn nhiều thời gian một lần duy nhất (như di chuyển dữ liệu hoặc xuất báo cáo nặng), hãy chạy lệnh này trong trình soạn thảo SQL trước khi thực thi truy vấn chính của bạn:
-- Vô hiệu hóa timeout cho session hiện tại
SET statement_timeout = 0;
-- Hoặc đặt một khoảng thời gian cụ thể (ví dụ: 5 phút)
SET statement_timeout = '5min';
Để kiểm tra thiết lập timeout hiện tại, hãy chạy:
SHOW statement_timeout;
Tại sao lỗi này xảy ra
Lỗi ERROR: canceling statement due to statement timeout xảy ra vì máy chủ PostgreSQL giới hạn thời gian thực thi của một câu lệnh SQL đơn lẻ. Khi một truy vấn vượt quá giới hạn này, máy chủ sẽ dừng tiến trình để ngăn nó tiêu tốn tài nguyên hệ thống vô thời hạn.
Giới hạn này được kiểm soát bởi tham số statement_timeout. Mặc dù giá trị mặc định thường là 0 (không giới hạn timeout), nhiều dịch vụ cơ sở dữ liệu được quản lý (như AWS RDS) hoặc các quản trị viên cơ sở dữ liệu (DBA) thường đặt giới hạn mặc định (ví dụ: 30 giây hoặc 60 giây) để duy trì khả năng phản hồi của hệ thống.
Cách khắc phục lỗi
Cách 1: Thay đổi timeout cho session hiện tại
Đây là phương pháp an toàn nhất vì nó chỉ ảnh hưởng đến kết nối hiện tại của bạn. Phương pháp này rất lý tưởng cho các tác vụ chỉ chạy một lần.
-- Đặt timeout thành 10 phút chỉ cho session này
SET statement_timeout = '10min';
-- Chạy truy vấn nặng của bạn tại đây
SELECT * FROM large_table JOIN another_large_table ...;
Cách 2: Thay đổi timeout cho một user hoặc database cụ thể
Nếu bạn có một user chuyên chạy các tác vụ chạy ngầm (background worker) luôn thực hiện các công việc dài hạn, bạn có thể tăng giới hạn riêng cho user đó mà không ảnh hưởng đến phần còn lại của ứng dụng.
-- Áp dụng cho một user cụ thể
ALTER ROLE reports_user SET statement_timeout = '1 hour';
-- Áp dụng cho một database cụ thể
ALTER DATABASE analytics_db SET statement_timeout = '30min';
Cách 3: Thay đổi cấu hình toàn cục
Để thay đổi giới hạn cho mọi kết nối đến máy chủ, hãy chỉnh sửa tệp postgresql.conf. Lưu ý rằng việc này yêu cầu quyền superuser và có thể cần tải lại cấu hình.
- Tìm tệp
postgresql.confcủa bạn. - Tìm dòng có chứa
statement_timeout. - Thay đổi giá trị (giá trị tính bằng mili giây nếu không chỉ định đơn vị).
# Đặt timeout toàn cục thành 2 phút
statement_timeout = 120000
Sau khi lưu, hãy tải lại cấu hình:
SELECT pg_reload_conf();
Cách 4: Tối ưu hóa truy vấn (Giải pháp lâu dài)
Tăng timeout thường chỉ là giải pháp tạm thời. Nếu một truy vấn từng chạy nhanh mà giờ lại bị timeout, bạn nên điều tra lý do tại sao nó chậm bằng cách sử dụng EXPLAIN ANALYZE.
EXPLAIN ANALYZE
SELECT * FROM orders
WHERE created_at > '2023-01-01'
ORDER BY total_amount DESC;
Hãy tìm các Seq Scan (Quét tuần tự) trên các bảng lớn. Thêm một index còn thiếu thường là cách tốt nhất để ngăn chặn lỗi timeout xảy ra ngay từ đầu.
Kiểm tra
Để xác nhận rằng các thay đổi của bạn đã có hiệu lực, hãy chạy lệnh sau trong cùng môi trường nơi bạn gặp lỗi:
SHOW statement_timeout;
Nếu kết quả hiển thị 0, nghĩa là timeout đã được tắt. Nếu hiển thị một giá trị như 5min, đó chính là giới hạn mới của bạn. Hãy thử chạy lại truy vấn; giờ đây nó sẽ có thể chạy vượt qua giới hạn thời gian trước đó.

