PostgreSQL
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> PostgreSQL

Tại sao PostgreSQL gọi hàm STABLE / IMMUTABLE của tôi nhiều lần?

Phần mở rộng sau của mã thử nghiệm 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

ĐẦU RA:

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 trong danh sách chọn, hàm không thay đổi được gọi nhiều lần, trong mệnh đề where nó được gọi một lần, trong khi hàm biến đổi đượ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 hoạt động một lần với cùng một dữ liệu - ví dụ của bạn cho thấy rõ ràng rằng đây không phải là trường hợp - đó là nó có thể chỉ gọi nó 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.v.

Có nhiều cách khác nhau để tận dụng tính ổn định và tính bất biến, với các chi phí và lợi ích khác nhau. Để cung cấp kiểu lưu mà bạn đang đề xuất, nó nên thực hiện với danh sách chọn, nó sẽ phải lưu kết quả vào bộ nhớ cache và sau đó tra cứu từng đối số (hoặc danh sách đối số) trong bộ nhớ cache này trước khi trả về kết quả đã lưu trong bộ nhớ cache hoặc hàm gọi trên bộ nhớ cache -bỏ lỡ. Điều này sẽ tốn kém hơn so với việc gọi hàm 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% số lần truy cập bộ nhớ cache có nghĩa là "tối ưu hóa" này đã hoạt động thêm mà hoàn toàn không có lợi). Nó có thể lưu trữ có thể chỉ là tham số và kết quả cuối cùng, nhưng một lần nữa điều đó có thể hoàn toàn vô dụng.

Điều này đặc biệt nên xem xét rằng 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.

Tuy nhiên, với mệnh đề where, tính bất biến của test_multi_calls1 cho phép PostgreSQL thực sự tái cấu trúc truy vấn theo nghĩa đơn giản của SQL đã cho:

Đối với một kế hoạch truy vấn hoàn toàn khác:

Đây là kiểu sử dụng mà PostgreSQL tạo ra ỔN ĐỊNH và ỔN ĐỊNH - không phải là bộ nhớ đệm của các kết quả, mà là việc viết lại các truy vấn thành các truy vấn khác nhau hiệu quả hơn nhưng cho cùng một kết quả.

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ả về (thay thế = 30 với = 31 để kiểm tra) thì hàm dễ bay hơi sẽ không được gọi - một lần nữa bất kể nó nằm ở phía nào của and .

Kiểu viết lại cụ thể này phụ thuộc vào tính bất biến hoặc tính ổn định. Với where test_multi_calls1(30) != num việc ghi lại truy vấn sẽ xảy ra đối với bất biến nhưng không xảy ra đối với các hàm ổn định đơn thuần. Với where test_multi_calls1(num) != 30 nó hoàn toàn không xảy ra (nhiều cuộc gọi) mặc dù có những cách tối ưu khác có thể:

Các biểu thức chỉ chứa các hàm ỔN ĐỊNH và ỔN ĐỊNH có thể được sử dụng khi quét chỉ mục. Các biểu thức có chứa hàm VOLATILE không được. Số lượng cuộc gọi có thể giảm hoặc không, nhưng quan trọng hơn nhiều là kết quả của các cuộc gọi sau đó sẽ được sử dụng theo cách hiệu quả hơn nhiều 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, nhưng sau đó nó có thể tạo ra một lượng lớn khác biệt).

Nói chung, đừng nghĩ đến các danh mục biến động về mặt ghi nhớ, mà hãy nghĩ về việc tạo cơ hội cho người lập kế hoạch truy vấn của PostgreSQL để tái cấu trúc toàn bộ truy vấn theo những cách tương đương về mặt logic (cùng kết quả) nhưng hiệu quả hơn nhiều.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. SQL đã tham gia vào ngày cuối cùng

  2. Tải xuống một phần cơ sở dữ liệu từ heroku

  3. Cách cài đặt PostgreSQL 12 trên Ubuntu 20.04 DigitalOcean

  4. JDBC - chọn nơi cột là NULL

  5. không thể ghi vào tệp nhật ký pg_upgrade_internal.log khi nâng cấp từ Postgresql 9.1 lên 9.3