Wrapper di dati esteri
In genere, i join o qualsiasi tabella derivata da sottoquery o CTE non sono disponibili sul server esterno e devono essere eseguiti localmente. Cioè, tutte le righe rimanenti dopo il semplice WHERE
clausola nel tuo esempio deve essere recuperata ed elaborata localmente come hai osservato.
Se tutto il resto fallisce puoi eseguire la sottoquery SELECT id FROM lookup_table WHERE x = 5
e concatena i risultati nella stringa di query.
Più convenientemente, puoi automatizzarlo con SQL dinamico e EXECUTE
in una funzione PL/pgSQL. Come:
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;
Correlati:
- Nome tabella come parametro di funzione PostgreSQL
Oppure prova questa ricerca su SO.
Oppure potresti usare il meta-comando \gexec
in psql. Vedi:
- Filtra i nomi delle colonne dalla tabella esistente per l'istruzione SQL DDL
Oppure questo potrebbe funzionare: (Il feedback dice che non funziona .)
SELECT id,c1,c2,c3
FROM big_table
WHERE c1 = 2
AND id = ANY (ARRAY(SELECT id FROM lookup_table WHERE x = 5));
Testando localmente, ottengo un piano di query come questo:
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)
Enfasi in grassetto la mia.
Il parametro $0
nel piano ispira speranza. L'array generato potrebbe essere qualcosa che Postgres può trasmettere per essere utilizzato in remoto. Non vedo un piano simile con nessuno dei tuoi altri tentativi o altri che ho provato io stesso. Puoi provare con il tuo fdw?
Domanda correlata relativa a postgres_fdw
:
- postgres_fdw:è possibile inviare i dati a un server esterno per l'adesione?
Tecnica generale in SQL
Questa è una storia diversa. Basta usare un CTE. Ma non mi aspetto che questo aiuti con 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 comportamento modificato (migliorato), in modo che le CTE possano essere integrate come sottoquery, date alcune precondizioni. Ma, citando il manuale:
Puoi ignorare tale decisione specificando MATERIALIZED
per forzare il calcolo separato della query WITH
Quindi:
WITH cte AS MATERIALIZED (SELECT id FROM lookup_table WHERE x = 5)
...
In genere, nulla di tutto ciò dovrebbe essere necessario se il server DB è configurato correttamente e le statistiche delle colonne sono aggiornate. Ma ci sono casi d'angolo con una distribuzione dei dati non uniforme...