Tối ưu hóa tham gia / truy vấn đắt tiền bằng cách lọc với các điều kiện


7

Đây là một câu hỏi về các THAM GIA đắt tiền hoặc các truy vấn phụ trong Postgresql (9.5 hoặc 9.6). Tôi cũng muốn nghe cách mọi người nói chung giải quyết vấn đề kiểm tra sau đó thực thi.

Tôi đang viết rất nhiều truy vấn chỉ nên trả về một cách có điều kiện một kết quả, chẳng hạn như nếu người dùng (web) sở hữu bản ghi hoặc nếu bản ghi bị sửa đổi. Tôi đang cố gắng ngăn chặn việc xây dựng các chế độ xem đắt tiền bên trong Postgresql và nhiều truy vấn qua lại để kiểm tra các điều kiện trong chính ứng dụng, vì vậy tôi cố gắng viết các truy vấn trước tiên chọn bản ghi chính xác và hiển thị các điều kiện không thành công và chỉ thực hiện xem nếu điều kiện vượt qua.

Chẳng hạn, điều này kiểm tra xem người dùng (ứng dụng) có sở hữu một bản ghi hay không trước khi trả lại:

SELECT is_owner, is_newer, json 
FROM (
     SELECT id, owner = '053bffbc-c41e-dad4-853b-ea91fc42ea18' "is_owner"
          , modified >= created "is_newer" 
     FROM datasets 
     WHERE id = '056e4eed-ee63-2add-e981-0c86b8b6a66f'
) cond
LEFT JOIN LATERAL (
     SELECT id 
     FROM datasets 
     WHERE is_owner and is_newer
) authed
    ON cond.id = authed.id
LEFT JOIN LATERAL (
     SELECT json 
     FROM view_dataset 
     WHERE id = authed.id
) dataset
    ON true;

Kết quả là (là chủ sở hữu):

is_owner | is_newer | json
t          t          {...}

Và kết quả âm tính (không phải chủ sở hữu):

is_owner | is_newer | json
f          t          NULL

Vì vậy, ứng dụng biết lỗi nào sẽ trả về nhưng chúng ta không phải xây dựng hoặc phân tích khung nhìn nếu các điều kiện không vượt qua.

Tuy nhiên, GIẢI THÍCH ANALYZE cho thấy Postgresql vẫn thực hiện truy vấn xem trong THAM GIA LÃNH ĐẠO cuối cùng mặc dù THAM GIA giữa không có bất kỳ kết quả nào và tôi không thể đưa nó vào trạng thái ngắn mạch để ngăn không cho CHỌN view_dataset CHỌN chạy . Nếu tôi đặt jsoncho nulltất cả những câu hỏi bỏ qua nhưng SELECT đầu tiên; nhưng nếu nó được đặt thành một giá trị từ truy vấn cuối cùng, nó sẽ luôn thực thi tất cả các CHỌN, vì vậy tôi đoán rằng trình hoạch định truy vấn nghĩ rằng nó phải có kết quả cho jsontrường đó trong truy vấn CHỌN hàng đầu và không làm ngắn mạch các THAM GIA .

Tôi tự hỏi nếu tôi có thể buộc Postgresql bỏ truy vấn xem đắt tiền.

Tôi cũng đã thử CTE, dường như bỏ qua truy vấn THAM GIA:

WITH cond as (
    SELECT id, owner = '053bffbc-c41e-dad4-853b-ea91fc42ea18' "is_owner", modified >= created "is_newer" FROM datasets WHERE id = '056e4eed-ee63-2add-e981-0c86b8b6a66f'
)
SELECT cond.id, cond.is_owner, cond.is_newer, json FROM
    (SELECT id FROM cond WHERE cond.is_owner and cond.is_newer) filtered
    LEFT JOIN LATERAL
    (SELECT id, json from view_dataset) dataset
    USING (id)
    RIGHT JOIN cond
    USING(id);

... nhưng truy vấn và các biến thể này chậm hơn ít nhất 2 lần.

Vì vậy, câu hỏi của tôi là làm thế nào để tối đa hóa hiệu suất bằng cách THAM GIA ngắn mạch hoặc truy vấn con dựa trên các điều kiện; và tôi cũng muốn biết liệu ai đó có ý tưởng khác về cách triển khai một số mẫu kiểm tra trước-sau-sau-thực hiện, chẳng hạn như kiểm tra quyền sở hữu bản ghi.


Không phải là một câu trả lời cho câu hỏi của bạn, nhưng bạn có thể tìm thấy một số quan tâm trong bài viết sau của dba.stackexchange.com/users/2512/lukas-eder : blog.jooq.org/2017/09/11/ trên
Lennart

Điều gì xảy ra nếu bạn thay đổi: ) dataset ON true;thành ) dataset ON is_owner;?
Lennart

Câu trả lời:


1

Không chắc chắn tại sao authedcần thiết cả. Làm gì

SELECT is_owner, is_newer, json 
FROM (
     SELECT id, owner = '053bffbc-c41e-dad4-853b-ea91fc42ea18' "is_owner"
          , modified >= created "is_newer" 
     FROM datasets 
     WHERE id = '056e4eed-ee63-2add-e981-0c86b8b6a66f'
) cond
LEFT JOIN LATERAL (
     SELECT json 
     FROM view_dataset 
     WHERE id = cond.id
) dataset
    ON is_owner and is_newer;

bởi bạn? Tôi cũng đồng ý với nhận xét của a_horse_with_no_name . LATITH có thể là một trợ giúp to lớn để đẩy các vị từ xuống các bảng cơ sở trong các trường hợp đặc biệt, nhưng nó chỉ là một truy vấn phụ được ngụy trang nên trong hầu hết các trường hợp, việc tham gia bình thường sẽ có ý nghĩa hơn. Cũng thử:

SELECT is_owner, is_newer, json 
FROM (
     SELECT id, owner = '053bffbc-c41e-dad4-853b-ea91fc42ea18' "is_owner"
          , modified >= created "is_newer" 
     FROM datasets 
     WHERE id = '056e4eed-ee63-2add-e981-0c86b8b6a66f'
) cond
LEFT JOIN view_dataset wd
    ON wd.id = cond.id 
   AND cond.is_owner 
   AND cond.is_newer;

BIÊN TẬP. bảng chức năng có giá trị

CREATE FUNCTION get_view_dataset(int,bool) 
    RETURNS setof view_dataset AS '
        SELECT * 
        FROM view_dataset wd
        WHERE wd.id = $1 
          AND $2;
    ' LANGUAGE SQL;

và sau đó sử dụng chức năng đó trong truy vấn của bạn dưới dạng:

SELECT is_owner, is_newer, json 
FROM (
     SELECT id, owner = '053bffbc-c41e-dad4-853b-ea91fc42ea18' "is_owner"
          , modified >= created "is_newer" 
     FROM datasets 
     WHERE id = '056e4eed-ee63-2add-e981-0c86b8b6a66f'
) cond
LEFT JOIN get_view_dataset(cond.id, cond.is_owner AND cond.is_newer);

Tất cả chưa được kiểm tra.


Ngoài ra: tham gia bên không nhất thiết phải nhanh hơn. Tôi cũng sẽ thửleft join view_dataset as dataset on dataset.id = cond.id and cond.is_owner and cond.is_newer
a_horse_with_no_name

Tôi đồng ý, tôi cập nhật câu trả lời của tôi. Nếu bạn muốn thêm một câu trả lời của riêng tôi, tôi có thể loại bỏ phần đó.
Lennart

Tất cả đều hoạt động tốt, nhưng vẫn chạy chế độ xem đắt tiền trong lựa chọn cuối cùng (ít nhất là vào ngày 9.5). Tham gia bên giữa là cần thiết để đi từ 1 bản ghi khớp trong truy vấn đầu tiên về 0 trong chế độ xem thứ ba (chế độ xem thực tế) để chế độ xem thứ ba không bao giờ được thực hiện nếu không cần thiết. Công cụ lập kế hoạch khăng khăng chạy chế độ xem đó nếu bất kỳ trường nào của nó được đề cập trong phần chọn chính (đó là trường "json"), bất chấp các điều kiện.
wvh

Hàm giá trị bảng có giúp (sắp xếp dạng xem được tham số hóa) không? Tôi sẽ thêm một ví dụ.
Lennart

1
Tôi đã tạo ra một câu đố SQL để giúp dễ dàng nhìn thấy những gì chiêng.
wvh
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.