Utländsk dataomslag
Vanligtvis är anslutningar eller andra härledda tabeller från underfrågor eller CTE:er inte tillgängliga på den främmande servern och måste exekveras lokalt. Dvs alla rader kvar efter den enkla WHERE
klausulen i ditt exempel måste hämtas och bearbetas lokalt som du observerade.
Om allt annat misslyckas kan du köra underfrågan SELECT id FROM lookup_table WHERE x = 5
och sammanfoga resultaten i frågesträngen.
Mer bekvämt kan du automatisera detta med dynamisk SQL och EXECUTE
i en PL/pgSQL-funktion. Gilla:
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;
Relaterat:
- Tabellnamn som en PostgreSQL-funktionsparameter
Eller prova den här sökningen på SO.
Eller så kan du använda metakommandot \gexec
i psql. Se:
- Filtrera kolumnnamn från befintlig tabell för SQL DDL-sats
Eller det här kan fungera: (Feedback säger att fungerar inte .)
SELECT id,c1,c2,c3
FROM big_table
WHERE c1 = 2
AND id = ANY (ARRAY(SELECT id FROM lookup_table WHERE x = 5));
När jag testar lokalt får jag en frågeplan så här:
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)
Djärv betoning min.
Parametern $0
i planen inger hopp. Den genererade arrayen kan vara något som Postgres kan skicka vidare för att användas på distans. Jag ser inte en liknande plan med några av dina andra försök eller några fler som jag försökte själv. Kan du testa med din fdw?
Relaterad fråga om postgres_fdw
:
- postgres_fdw:möjligt att skicka data till främmande server för att ansluta?
Allmän teknik i SQL
Det är en annan historia. Använd bara en CTE. Men jag förväntar mig inte att det hjälper med 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 ändrat (förbättrat) beteende, så att CTE:er kan infogas som underfrågor, givet vissa förutsättningar. Men citerar manualen:
Du kan åsidosätta det beslutet genom att ange
MATERIALIZED
för att tvinga fram separat beräkning av WITH-frågan
Så:
WITH cte AS MATERIALIZED (SELECT id FROM lookup_table WHERE x = 5)
...
Vanligtvis bör inget av detta vara nödvändigt om din DB-server är korrekt konfigurerad och kolumnstatistiken är uppdaterad. Men det finns hörnfall med ojämn datafördelning ...