PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

So erzwingen Sie die Auswertung der Unterabfrage vor dem Beitritt / Pushdown auf einen fremden Server

Wrapper für fremde Daten

Typischerweise sind Joins oder abgeleitete Tabellen von Unterabfragen oder CTEs nicht auf dem fremden Server verfügbar und müssen lokal ausgeführt werden. Das heißt, alle Zeilen, die nach dem einfachen WHERE verbleiben -Klausel in Ihrem Beispiel müssen abgerufen und lokal verarbeitet werden, wie Sie es beobachtet haben.

Wenn alles andere fehlschlägt, können Sie die Unterabfrage SELECT id FROM lookup_table WHERE x = 5 ausführen und Ergebnisse in der Abfragezeichenfolge verketten.

Bequemer können Sie dies mit dynamischem SQL und EXECUTE automatisieren in einer PL/pgSQL-Funktion. Wie:

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;

Verwandte:

  • Tabellenname als PostgreSQL-Funktionsparameter

Oder versuchen Sie diese Suche auf SO.

Oder Sie verwenden den Meta-Befehl \gexec im psql. Siehe:

  • Spaltennamen aus vorhandener Tabelle für SQL-DDL-Anweisung filtern

Oder das könnte funktionieren: (Feedback sagt funktioniert nicht .)

SELECT id,c1,c2,c3
FROM   big_table
WHERE  c1 = 2
AND    id = ANY (ARRAY(SELECT id FROM lookup_table WHERE x = 5));

Beim lokalen Testen erhalte ich einen Abfrageplan wie diesen:

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)

Fettdruck von mir.

Der Parameter $0 im Plan flößt Hoffnung ein. Das generierte Array könnte etwas sein, das Postgres zur Remote-Verwendung weitergeben kann. Ich sehe keinen ähnlichen Plan bei Ihren anderen Versuchen oder bei einigen, die ich selbst ausprobiert habe. Kannst du das mit deinem fdw testen?

Verwandte Frage zu postgres_fdw :

  • postgres_fdw:möglich, Daten zum Beitritt auf einen fremden Server zu pushen?

Allgemeine Technik in SQL

Das ist eine andere Geschichte. Verwenden Sie einfach einen CTE. Aber ich erwarte nicht, dass das beim FDW hilft.

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 geändertes (verbessertes) Verhalten, sodass CTEs unter bestimmten Voraussetzungen wie Unterabfragen eingebunden werden können. Aber das Handbuch zitierend:

Sie können diese Entscheidung überschreiben, indem Sie MATERIALIZED angeben separate Berechnung der WITH-Abfrage zu erzwingen

Also:

WITH cte AS MATERIALIZED (SELECT id FROM lookup_table WHERE x = 5)
...

Normalerweise sollte nichts davon erforderlich sein, wenn Ihr DB-Server ordnungsgemäß konfiguriert ist und die Spaltenstatistiken auf dem neuesten Stand sind. Aber es gibt Eckfälle mit ungleichmäßiger Datenverteilung ...