PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

Come forzare la valutazione della sottoquery prima di entrare / spingere verso il basso su un server esterno

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...