2017-05-05 18 views
5

Hãy xem xét các truy vấn sql sau:truy vấn dữ liệu thông minh hiệu suất chức năng bên trong cho PostgreSQL

SELECT a,b,c 
FROM t 
WHERE (id1 = :p_id1 OR :p_id1 IS NULL) AND (id2 = :p_id2 OR :p_id2 IS NULL) 

Markus Winand trong cuốn sách của ông "SQL Performance explained" tên phương pháp này như một trong những hoạt động tồi tệ nhất chống mẫu của tất cả, và giải thích tại sao (cơ sở dữ liệu phải chuẩn bị kế hoạch cho trường hợp xấu nhất khi tất cả các bộ lọc bị tắt).

Nhưng sau đó, ông cũng viết cho PostgreSQL vấn đề này xảy ra chỉ khi tái sử dụng một tuyên bố (PreparedStatement) xử lý.

cũng Giả sử bây giờ mà truy vấn trên được gói vào chức năng, một cái gì đó như:

CREATE FUNCTION func(IN p_id1 BIGINT,IN p_id2 BIGINT) 
... 
$BODY$ 
    BEGIN 
    ... 
    END; 
$BODY$ 

Cho đến nay tôi có sự hiểu lầm trong số ít điểm:

  1. sẽ vấn đề này vẫn xảy ra trong trường hợp chức năng gói? (Tôi đã cố gắng để xem kế hoạch thực hiện cho các cuộc gọi chức năng, nhưng Postgres không hiển thị cho tôi các chi tiết cho các cuộc gọi chức năng nội bộ ngay cả với SET auto_explain.log_nested_statements = ON).

  2. Giả sử tôi đang làm việc với dự án cũ và không thể thay đổi chính chức năng, chỉ mã thực thi java. Sẽ tốt hơn nếu bạn tránh báo cáo đã chuẩn bị ở đây và sử dụng truy vấn động mỗi lần? (Giả sử thời gian thực hiện là khá dài, lên đến vài giây). Nói điều này, có lẽ, xấu xí cách tiếp cận:


getSession().doWork(connection -> { 
    ResultSet rs = connection.createStatement().executeQuery("select * from func("+id1+","+id2+")"); 
    ... 
}) 

Trả lời

2

1. Nó phụ thuộc.

Khi không sử dụng các câu lệnh chuẩn bị, PostgreSQL lập kế hoạch truy vấn mỗi lần một lần nữa, sử dụng các giá trị tham số. Nó được gọi là gói tùy chỉnh.

Với các câu lệnh chuẩn bị (và bạn nói đúng, các hàm PL/pgSQL sử dụng các câu lệnh đã chuẩn bị) nó phức tạp hơn. PostgreSQL chuẩn bị câu lệnh (phân tích văn bản của nó và lưu trữ cây phân tích cú pháp), nhưng lại lên kế hoạch mỗi khi nó được thực thi. Gói tùy chỉnh được tạo ít nhất 5 lần. Sau đó, người lập kế hoạch xem xét sử dụng kế hoạch chung (i. E. Thông số-giá trị độc lập) nếu chi phí thấp hơn chi phí trung bình của các gói tùy chỉnh được tạo cho đến thời điểm này.

Lưu ý rằng chi phí của kế hoạch là ước tính của nhà lập kế hoạch, không phải là các hoạt động I/O hoặc chu kỳ CPU thực.

Vì vậy, vấn đề có thể xảy ra, nhưng bạn cần một số may mắn cho điều đó.

2. Cách tiếp cận bạn đề xuất sẽ không hoạt động, vì nó không thay đổi hành vi của hàm.

Nói chung nó không quá xấu xí đối với PostgreSQL không sử dụng các tham số (vì nó dành cho e. G. Oracle), vì PostgreSQL không có bộ nhớ cache dùng chung cho các gói. Kế hoạch chuẩn bị được lưu trữ trong bộ nhớ của mỗi phụ trợ, vì vậy việc lập kế hoạch lại sẽ không ảnh hưởng đến các phiên khác.

Nhưng theo như tôi biết, hiện tại không có cách nào để buộc người lập kế hoạch sử dụng các gói tùy chỉnh (ngoài kết nối lại sau 5 lần thực thi ...).

+0

Cảm ơn câu trả lời của bạn. Về điểm 1 tôi không hiểu lắm. Nó có nghĩa là vấn đề được mô tả nói chung không phải là một vấn đề cho PostgreSQL khi loại truy vấn như vậy được bao bọc trong hàm? – Andremoniy

+0

Nó thực sự phụ thuộc vào may mắn. Cho phép nói truy vấn có một tham số và rất cần kế hoạch khác nhau cho các giá trị A và B. Ví dụ, A yêu cầu quét tuần tự (chi phí cao), trong khi B có lợi từ quét chỉ mục (chi phí thấp). Kế hoạch chung sử dụng quét tuần tự. Bạn thực thi F (A) 5 lần và người lập kế hoạch quyết định rằng bạn có thể chuyển sang kế hoạch chung. Bây giờ bạn có một vấn đề: F (B) sẽ không sử dụng quét chỉ mục. Nhưng nếu bạn gọi F (A), F (B), F (A), F (B) và như vậy, chi phí tùy chỉnh trung bình sẽ nhỏ hơn chi phí của kế hoạch chung và bạn được an toàn. –

+0

Được rồi, nhưng tôi nghĩ chúng ta luôn nên xem xét trường hợp xấu nhất, phải không? Có vẻ như trong trường hợp xấu nhất nó vẫn sẽ là vấn đề. Và tôi có hiểu chính xác rằng đối với một chức năng, kế hoạch sẽ được tính toán bất kể sử dụng câu lệnh đã chuẩn bị chưa? – Andremoniy

Các vấn đề liên quan