Postgres sẽ thực hiện tính toán các cột được tính toán không được chọn trong chế độ xem?


8

Tôi đang cố gắng hiểu tác động hiệu suất của việc chọn dữ liệu từ chế độ xem, trong đó một trong các cột trong chế độ xem là chức năng của dữ liệu khác trong bảng gốc.

Việc tính toán có được thực hiện bất kể liệu cột được tính có trong danh sách các cột được chọn hay không?

Nếu tôi có một bảng và khung nhìn được tuyên bố như vậy

CREATE TABLE price_data (
    ticker     text,          -- Ticker of the stock
    ddate      date,          -- Date for this price
    price      float8,        -- Closing price on this date
    factor     float8         -- Factor to convert this price to USD
);

CREATE VIEW prices AS 
    SELECT ticker, 
           ddate,
           price,
           factor,
           price * factor as price_usd
    FROM price_data

Would rằng nhân được thực hiện trong một truy vấn như hình dưới đây?

select ticker, ddate, price, factor from prices

Có một tài liệu tham khảo đảm bảo cách này hay cách khác? Tôi đã đọc tài liệu về hệ thống quy tắc trong Postgres, nhưng tôi nghĩ câu trả lời thực sự nằm ở trình tối ưu hóa, vì không có gì trong tài liệu hệ thống quy tắc chỉ ra rằng nó sẽ không được chọn.

Tôi nghi ngờ trong trường hợp trên, việc tính toán không được thực hiện. Tôi đã thay đổi quan điểm để phân chia sử dụng thay vì nhân, và chèn một 0cho factorvào price_data. Truy vấn trên không thất bại, nhưng nếu truy vấn được sửa đổi để chọn cột được tính thì truy vấn đã sửa đổi không thành công.

Có cách nào để hiểu những tính toán nào đang được thực hiện khi selectthực hiện không? Tôi đoán tôi đang tìm kiếm một cái gì đó giống như EXPLAINnhưng nó cũng cho tôi biết về (các) tính toán đang được thực hiện.


1
Đây là một câu hỏi xuất sắc thuộc loại chúng tôi muốn khuyến khích trên SE này
Gaius

Câu trả lời:


6

Như @Laurenz đã nói, phân tích của bạn là chính xác: trình tối ưu hóa sẽ tránh đánh giá các biểu thức cột không ảnh hưởng đến kết quả của truy vấn (và nỗ lực của bạn để buộc lỗi chia cho 0 là bằng chứng về điều này).

Điều này phụ thuộc vào cột bạn đang chọn, nhưng nó cũng phụ thuộc vào loại biến động của biểu thức cột. Trình tối ưu hóa có thể tự do bỏ qua immutablestablegọi hàm nếu đầu ra của chúng không bao giờ được sử dụng, vì chúng không thể ảnh hưởng đến kết quả, nhưng các volatilechức năng có thể có tác dụng phụ, vì vậy chúng không được tối ưu hóa dễ dàng như vậy.

Ví dụ:

create function stable_function() returns int as $$
begin
  raise notice 'stable_function() called';
  return 1;
end
$$
language plpgsql stable;

create function volatile_function() returns int as $$
begin
  raise notice 'volatile_function() called';
  return 1;
end
$$
language plpgsql volatile;

create view v as
  select stable_function(), volatile_function();

Nếu chỉ có volatilecột được chọn:

test=# explain (analyse, verbose) select volatile_function from v;
NOTICE:  volatile_function() called
                                           QUERY PLAN
------------------------------------------------------------------------------------------------
 Subquery Scan on v  (cost=0.00..0.27 rows=1 width=4) (actual time=0.057..0.057 rows=1 loops=1)
   Output: v.volatile_function
   ->  Result  (cost=0.00..0.26 rows=1 width=8) (actual time=0.056..0.056 rows=1 loops=1)
         Output: NULL::integer, volatile_function()

... sau đó như bạn có thể thấy, stable_function()vắng mặt ở explainđầu ra và thiếu NOTICExác nhận rằng cuộc gọi này đã được tối ưu hóa.

Tuy nhiên, nếu stablecột được chọn thay thế:

test=# explain (analyse, verbose) select stable_function from v;
NOTICE:  stable_function() called
NOTICE:  volatile_function() called
                                           QUERY PLAN
------------------------------------------------------------------------------------------------
 Subquery Scan on v  (cost=0.00..0.52 rows=1 width=4) (actual time=0.139..0.139 rows=1 loops=1)
   Output: v.stable_function
   ->  Result  (cost=0.00..0.51 rows=1 width=8) (actual time=0.138..0.138 rows=1 loops=1)
         Output: stable_function(), volatile_function()

... sau đó chúng ta thấy cả hai biểu thức cột xuất hiện trong kế hoạch và NOTICEs cho thấy cả hai hàm đã được thực thi.

Dường như không có bất kỳ đề cập rõ ràng nào về hành vi này trong các tài liệu, vì vậy không có sự đảm bảo cứng nào về việc liệu một biểu thức sẽ được đánh giá hay không và bạn không nên dựa vào bất kỳ tác dụng phụ nào mà các lệnh gọi chức năng của bạn có thể có.

Nhưng nếu mối quan tâm duy nhất của bạn là hiệu suất, thì miễn là bạn đánh dấu các chức năng của mình là phù hợp stablehoặc immutablephù hợp, bạn có thể chắc chắn một cách hợp lý (đặc biệt trong các trường hợp đơn giản như thế này) rằng chúng sẽ không được đánh giá trừ khi chúng cần thiết.

(Và trong khi bạn đang kiểm tra các tuyên bố biến động của mình, bạn cũng có thể muốn đặt các cờ an toàn song song .)


1
"vì vậy nó sẽ được gọi bất kể" Nó sẽ được gọi theo bảo đảm của DBMS cụ thể. Trong đó có thể không có. Một truy vấn SQL mô tả một kết quả, không phải là một quá trình. Tài liệu PostgesSQL tái định dạng: Trình tối ưu hóa không đưa ra giả định nào về hoạt động của các chức năng đó. Một truy vấn sử dụng hàm dễ bay hơi sẽ đánh giá lại hàm ở mọi hàng nơi cần giá trị của nó. (Dù "cần thiết" có nghĩa là gì.)
philipxy

@philipxy: Bạn hoàn toàn đúng. Tôi không có ý ám chỉ bất kỳ sự đảm bảo nào ngoài những điều được nêu trong các tài liệu, mặc dù khi đọc lại, tôi chắc chắn đã làm. Hy vọng chỉnh sửa của tôi làm rõ mọi thứ. Cảm ơn!
Nick Barnes

4

Sự nghi ngờ của bạn là chính xác và không nên thực hiện tính toán nếu cột không được sử dụng.

Để xác nhận điều đó, hãy nhìn vào đầu ra của EXPLAIN (VERBOSE)truy vấn, nó sẽ hiển thị cho bạn các cột được trả về.

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.