Zahraniční obálka dat
Spojení nebo jakékoli odvozené tabulky z poddotazů nebo CTE obvykle nejsou na cizím serveru dostupné a musí být provedeny lokálně. Tj. všechny řádky zbývající po jednoduchém WHERE
klauzule ve vašem příkladu musí být načtena a zpracována místně, jak jste si všimli.
Pokud vše ostatní selže, můžete spustit poddotaz SELECT id FROM lookup_table WHERE x = 5
a zřetězit výsledky do řetězce dotazu.
Pohodlněji to můžete automatizovat pomocí dynamického SQL a EXECUTE
ve funkci PL/pgSQL. Jako:
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;
Související:
- Název tabulky jako parametr funkce PostgreSQL
Nebo zkuste toto vyhledávání na SO.
Nebo můžete použít meta-příkaz \gexec
v psql. Viz:
- Filtrujte názvy sloupců z existující tabulky pro příkaz SQL DDL
Nebo toto by mohlo fungovat: (Zpětná vazba říká, že nefunguje .)
SELECT id,c1,c2,c3
FROM big_table
WHERE c1 = 2
AND id = ANY (ARRAY(SELECT id FROM lookup_table WHERE x = 5));
Při místním testování dostanu plán dotazů jako tento:
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)
Odvážný důraz můj.
Parametr $0
v plánu vzbuzuje naději. Vygenerované pole může být něco, co může Postgres předat k použití na dálku. Nevidím podobný plán u žádného z vašich dalších pokusů nebo u dalších, které jsem sám vyzkoušel. Můžete testovat s vaším fdw?
Související otázka týkající se postgres_fdw
:
- postgres_fdw:je možné poslat data na cizí server pro připojení?
Obecná technika v SQL
To je jiný příběh. Stačí použít CTE. Ale neočekávám, že to pomůže s 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 změněné (vylepšené) chování, takže CTE mohou být zařazovány jako poddotazy za určitých předpokladů. Ale cituji manuál:
Toto rozhodnutí můžete přepsat zadáním
MATERIALIZED
vynutit samostatný výpočet dotazu WITH
Takže:
WITH cte AS MATERIALIZED (SELECT id FROM lookup_table WHERE x = 5)
...
Obvykle by nic z toho nemělo být nutné, pokud je váš DB server správně nakonfigurován a statistiky sloupců jsou aktuální. Existují však rohové případy s nerovnoměrným rozložením dat ...