Phần mở rộng sau đây của mã kiểm tra của bạn là thông tin:
CREATE OR REPLACE FUNCTION test_multi_calls1(one integer)
RETURNS integer
AS $BODY$
BEGIN
RAISE NOTICE 'Immutable called with %', one;
RETURN one;
END;
$BODY$ LANGUAGE plpgsql IMMUTABLE;
CREATE OR REPLACE FUNCTION test_multi_calls2(one integer)
RETURNS integer
AS $BODY$
BEGIN
RAISE NOTICE 'Volatile called with %', one;
RETURN one;
END;
$BODY$ LANGUAGE plpgsql VOLATILE;
WITH data AS
(
SELECT 10 AS num
UNION ALL SELECT 10
UNION ALL SELECT 20
)
SELECT test_multi_calls1(num)
FROM data
where test_multi_calls2(40) = 40
and test_multi_calls1(30) = 30
OUTPUT:
NOTICE: Immutable called with 30
NOTICE: Volatile called with 40
NOTICE: Immutable called with 10
NOTICE: Volatile called with 40
NOTICE: Immutable called with 10
NOTICE: Volatile called with 40
NOTICE: Immutable called with 20
Ở đây chúng ta có thể thấy rằng mặc dù trong danh sách lựa chọn các chức năng bất biến được gọi là nhiều lần, trong mệnh đề where nó được gọi một lần, trong khi biến động được gọi là ba lần.
Điều quan trọng không phải là PostgreSQL sẽ chỉ gọi một STABLE
hoặc IMMUTABLE
chức năng một lần với cùng một dữ liệu - ví dụ của bạn rõ ràng cho thấy rằng đây không phải là trường hợp - đó là nó có thể gọi nó là chỉ một lần. Hoặc có lẽ nó sẽ gọi nó hai lần khi nó sẽ phải gọi một phiên bản dễ bay hơi 50 lần, và cứ thế.
Có nhiều cách khác nhau trong đó tính ổn định và bất biến có thể được tận dụng, với chi phí và lợi ích khác nhau. Để cung cấp loại tiết kiệm bạn đang đề xuất nên chọn danh sách lựa chọn, nó sẽ phải lưu lại kết quả, sau đó tra cứu từng đối số (hoặc danh sách đối số) trong bộ đệm này trước khi trả về kết quả đã lưu trong bộ nhớ cache hoặc chức năng gọi trên bộ đệm -bỏ lỡ. Điều này sẽ đắt hơn gọi điện cho chức năng của bạn, ngay cả trong trường hợp có tỷ lệ truy cập bộ nhớ cache cao (có thể có 0% lần truy cập bộ nhớ cache có nghĩa là "tối ưu hóa" này đã làm thêm công việc để hoàn toàn không có được). Nó có thể lưu trữ có lẽ chỉ là tham số và kết quả cuối cùng, nhưng lại có thể hoàn toàn vô dụng.
Điều này đặc biệt để xem xét các chức năng ổn định và không thay đổi thường là các chức năng nhẹ nhất.
Với mệnh đề where Tuy nhiên, tính bất biến của test_multi_calls1
phép PostgreSQL để thực sự tái cấu trúc truy vấn từ ý nghĩa đơn giản của SQL đưa ra:
Đối với mỗi hàng tính toán test_multi_calls1 (30) và nếu kết quả là bằng 30 tiếp tục xử lý hàng trong câu hỏi
Đối với một kế hoạch truy vấn khác nhau hoàn toàn:
Tính test_multi_calls1 (30) và nếu nó là bằng 30 thì tiếp tục với các truy vấn khác trở lại một số không liên tiếp kết quả thiết lập mà không cần bất kỳ tính toán thêm
Đây là loại sử dụng mà PostgreSQL làm của ỔN ĐỊNH và IMMUTABLE - không phải là bộ nhớ đệm của kết quả, nhưng việc viết lại các truy vấn vào các truy vấn khác nhau có hiệu quả hơn nhưng cho kết quả tương tự.
Cũng lưu ý rằng test_multi_calls1 (30) được gọi trước test_multi_calls2 (40) bất kể thứ tự chúng xuất hiện trong mệnh đề where. Điều này có nghĩa là nếu cuộc gọi đầu tiên dẫn đến không có hàng nào được trả lại (thay thế = 30
với = 31
để kiểm tra) thì hàm không ổn định sẽ không được gọi - bất kể nó nằm ở bên nào của and
.
Loại ghi đè cụ thể này tùy thuộc vào tính bất biến hoặc độ ổn định. Với where test_multi_calls1(30) != num
truy vấn viết lại sẽ xảy ra cho bất biến nhưng không chỉ cho các chức năng đơn thuần ổn định. Với where test_multi_calls1(num) != 30
nó sẽ không xảy ra ở tất cả (nhiều cuộc gọi) mặc dù có các tối ưu hóa khác có thể:
Biểu thức chỉ có thể sử dụng chức năng Ổn định và IMMUTABLE. Biểu thức có chứa hàm VOLATILE không thể. Số lượng cuộc gọi có thể hoặc không giảm, nhưng quan trọng hơn nhiều là kết quả của các cuộc gọi sẽ được sử dụng theo cách hiệu quả hơn trong phần còn lại của truy vấn (chỉ thực sự quan trọng trên các bảng lớn) Sự khác biệt). Trong tất cả, đừng nghĩ đến các loại biến động về mặt memoisation, mà là về cơ hội lập kế hoạch truy vấn của PostgreSQL để tái cơ cấu toàn bộ truy vấn theo cách tương đương về mặt logic (cùng một kết quả) nhưng hiệu quả hơn nhiều.
Thú vị –