Trình bao bọc dữ liệu nước ngoài
Thông thường, các phép nối hoặc bất kỳ bảng dẫn xuất nào từ các truy vấn con hoặc CTE không có sẵn trên máy chủ nước ngoài và phải được thực thi cục bộ. Tức là tất cả các hàng còn lại sau WHERE
đơn giản mệnh đề trong ví dụ của bạn phải được truy xuất và xử lý cục bộ như bạn đã quan sát.
Nếu vẫn thất bại, bạn có thể thực hiện truy vấn con SELECT id FROM lookup_table WHERE x = 5
và nối kết quả vào chuỗi truy vấn.
Thuận tiện hơn, bạn có thể tự động hóa việc này bằng SQL động và EXECUTE
trong một hàm PL / pgSQL. Như:
CREATE OR REPLACE FUNCTION my_func(_c1 int, _l_id int)
RETURNS TABLE(id int, c1 int, c2 int, c3 int) AS
$func$
BEGIN
RETURN QUERY EXECUTE
'SELECT id,c1,c2,c3 FROM big_table
WHERE c1 = $1
AND id = ANY ($2)'
USING _c1
, ARRAY(SELECT l.id FROM lookup_table l WHERE l.x = _l_id);
END
$func$ LANGUAGE plpgsql;
Có liên quan:
- Tên bảng dưới dạng tham số hàm PostgreSQL
Hoặc thử tìm kiếm này trên SO.
Hoặc bạn có thể sử dụng meta-command \gexec
trong psql. Xem:
- Lọc tên cột từ bảng hiện có cho câu lệnh SQL DDL
Hoặc điều này có thể hoạt động: (Phản hồi cho biết không hoạt động .)
SELECT id,c1,c2,c3
FROM big_table
WHERE c1 = 2
AND id = ANY (ARRAY(SELECT id FROM lookup_table WHERE x = 5));
Đang kiểm tra cục bộ, tôi nhận được một kế hoạch truy vấn như sau:
Index Scan using big_table_idx on big_table (cost= ...) Index Cond: (id = ANY ($0)) Filter: (c1 = 2) InitPlan 1 (returns $0) -> Seq Scan on lookup_table (cost= ...) Filter: (x = 5)
Nhấn mạnh đậm của tôi.
Tham số $0
trong kế hoạch truyền cảm hứng cho hy vọng. Mảng được tạo có thể là thứ mà Postgres có thể chuyển để được sử dụng từ xa. Tôi không thấy một kế hoạch tương tự với bất kỳ nỗ lực nào khác của bạn hoặc một số kế hoạch khác mà tôi đã tự mình thử. Bạn có thể kiểm tra với fdw của bạn không?
Câu hỏi liên quan về postgres_fdw
:
- postgres_fdw:có thể đẩy dữ liệu sang máy chủ nước ngoài để tham gia không?
Kỹ thuật chung trong SQL
Đó là một câu chuyện khác. Chỉ cần sử dụng CTE. Nhưng tôi không hy vọng điều đó sẽ giúp ích cho FDW.
WITH cte AS (SELECT id FROM lookup_table WHERE x = 5)
SELECT id,c1,c2,c3
FROM big_table b
JOIN cte USING (id)
WHERE b.c1 = 2;
PostgreSQL 12 đã thay đổi (cải thiện) hành vi, để CTE có thể được nội tuyến giống như các truy vấn con, với một số điều kiện tiên quyết. Nhưng, trích dẫn sách hướng dẫn:
Bạn có thể ghi đè quyết định đó bằng cách chỉ định
MATERIALIZED
để buộc tính toán riêng truy vấn WITH
Vì vậy:
WITH cte AS MATERIALIZED (SELECT id FROM lookup_table WHERE x = 5)
...
Thông thường, không cần thiết trong số này nếu máy chủ DB của bạn được định cấu hình đúng cách và thống kê cột được cập nhật. Nhưng có những trường hợp góc với sự phân bố dữ liệu không đồng đều ...