PostgreSQL
 sql >> Baza danych >  >> RDS >> PostgreSQL

Jak wymusić ocenę podzapytania przed dołączeniem / zepchnięciem na zagraniczny serwer?

Opakowanie danych zagranicznych

Zazwyczaj złączenia lub wszelkie tabele pochodne z podzapytań lub CTE nie są dostępne na serwerze obcym i muszą być wykonywane lokalnie. Czyli wszystkie wiersze pozostałe po prostym WHERE klauzula w twoim przykładzie musi zostać pobrana i przetworzona lokalnie, tak jak zauważyłeś.

Jeśli wszystko inne zawiedzie, możesz wykonać podzapytanie SELECT id FROM lookup_table WHERE x = 5 i połącz wyniki w ciąg zapytania.

Wygodniej możesz to zautomatyzować za pomocą dynamicznego SQL i EXECUTE w funkcji PL/pgSQL. Na przykład:

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;

Powiązane:

  • Nazwa tabeli jako parametr funkcji PostgreSQL

Lub spróbuj tego wyszukiwania na SO.

Możesz też użyć metapolecenia \gexec w psql. Zobacz:

  • Przefiltruj nazwy kolumn z istniejącej tabeli dla instrukcji SQL DDL

Lub to może zadziałać: (Opinia mówi, że nie działa .)

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

Testując lokalnie, otrzymuję taki plan zapytań:

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)

Pogrubiony nacisk na moje.

Parametr $0 w planie budzi nadzieję. Wygenerowana tablica może być czymś, co Postgres może przekazać do zdalnego użycia. Nie widzę podobnego planu z żadną z twoich innych prób lub z niektórymi, których sam próbowałem. Czy możesz przetestować za pomocą fdw?

Powiązane pytanie dotyczące postgres_fdw :

  • postgres_fdw:czy można przesłać dane na obcy serwer w celu dołączenia?

Ogólna technika w SQL

To inna historia. Po prostu użyj CTE. Ale nie oczekuję, że to pomoże w 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 zmienione (ulepszone) zachowanie, dzięki czemu CTE mogą być wstawiane jak podzapytania, przy spełnieniu pewnych warunków wstępnych. Ale cytując instrukcję:

Możesz zmienić tę decyzję, określając MATERIALIZED aby wymusić oddzielne obliczanie zapytania WITH

A więc:

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

Zazwyczaj nie powinno to być konieczne, jeśli serwer bazy danych jest poprawnie skonfigurowany, a statystyki kolumn są aktualne. Ale są przypadki narożne z nierównym rozkładem danych ...




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Porównanie systemów równoważenia obciążenia dla PostgreSQL

  2. Jak uzyskać koniec dnia?

  3. błąd instrukcji sql:kolumna .. nie istnieje

  4. Iterowanie po liczbach całkowitych [] w PL/pgSQL

  5. Zwróć wiersze pasujące do elementów tablicy wejściowej w funkcji plpgsql