Обвивка на чужди данни
Обикновено присъединяванията или произведените таблици от подзаявки или CTE не са налични на чуждия сървър и трябва да се изпълняват локално. Т.е. всички редове, оставащи след простия WHERE
клаузата във вашия пример трябва да бъде извлечена и обработена локално, както сте забелязали.
Ако всичко друго не успее, можете да изпълните подзаявката SELECT id FROM lookup_table WHERE x = 5
и конкатенира резултатите в низа на заявката.
По-удобно е, че можете да автоматизирате това с динамичен SQL и EXECUTE
във функция PL/pgSQL. Като:
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;
Свързано:
- Име на таблица като параметър на функцията на PostgreSQL
Или опитайте това търсене на SO.
Или можете да използвате метакомандата \gexec
в psql. Вижте:
- Филтрирайте имената на колони от съществуваща таблица за SQL DDL израз
Или това може да работи: (Отзивите казват, че не работи .)
SELECT id,c1,c2,c3
FROM big_table
WHERE c1 = 2
AND id = ANY (ARRAY(SELECT id FROM lookup_table WHERE x = 5));
Тествайки локално, получавам план за заявка като този:
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)
Удебелен акцент мой.
Параметърът $0
в плана вдъхва надежда. Генерираният масив може да е нещо, което Postgres може да предаде, за да се използва отдалечено. Не виждам подобен план с други твои опити или други, които опитах сам. Можете ли да тествате с вашия fdw?
Свързан въпрос относно postgres_fdw
:
- postgres_fdw:възможно ли е изпращане на данни към чужд сървър за присъединяване?
Обща техника в SQL
Това е друга история. Просто използвайте CTE. Но не очаквам това да помогне с 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 променено (подобрено) поведение, така че CTE могат да бъдат вградени като подзаявки, като се имат предвид някои предварителни условия. Но, цитирайки ръководството:
Можете да отмените това решение, като посочите
MATERIALIZED
за да принудите отделно изчисление на заявката WITH
И така:
WITH cte AS MATERIALIZED (SELECT id FROM lookup_table WHERE x = 5)
...
Обикновено нищо от това не трябва да е необходимо, ако вашият DB сървър е конфигуриран правилно и статистиката на колоните е актуална. Но има ъглови случаи с неравномерно разпределение на данните ...