sql >> Databáze >  >> RDS >> PostgreSQL

Jak vynutit vyhodnocení poddotazu před připojením / posunutím na cizí server

Zahraniční obálka dat

Spojení nebo jakékoli odvozené tabulky z poddotazů nebo CTE obvykle nejsou na cizím serveru dostupné a musí být provedeny lokálně. Tj. všechny řádky zbývající po jednoduchém WHERE klauzule ve vašem příkladu musí být načtena a zpracována místně, jak jste si všimli.

Pokud vše ostatní selže, můžete spustit poddotaz SELECT id FROM lookup_table WHERE x = 5 a zřetězit výsledky do řetězce dotazu.

Pohodlněji to můžete automatizovat pomocí dynamického SQL a EXECUTE ve funkci PL/pgSQL. Jako:

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;

Související:

  • Název tabulky jako parametr funkce PostgreSQL

Nebo zkuste toto vyhledávání na SO.

Nebo můžete použít meta-příkaz \gexec v psql. Viz:

  • Filtrujte názvy sloupců z existující tabulky pro příkaz SQL DDL

Nebo toto by mohlo fungovat: (Zpětná vazba říká, že nefunguje .)

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

Při místním testování dostanu plán dotazů jako tento:

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)

Odvážný důraz můj.

Parametr $0 v plánu vzbuzuje naději. Vygenerované pole může být něco, co může Postgres předat k použití na dálku. Nevidím podobný plán u žádného z vašich dalších pokusů nebo u dalších, které jsem sám vyzkoušel. Můžete testovat s vaším fdw?

Související otázka týkající se postgres_fdw :

  • postgres_fdw:je možné poslat data na cizí server pro připojení?

Obecná technika v SQL

To je jiný příběh. Stačí použít CTE. Ale neočekávám, že to pomůže s 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 změněné (vylepšené) chování, takže CTE mohou být zařazovány jako poddotazy za určitých předpokladů. Ale cituji manuál:

Toto rozhodnutí můžete přepsat zadáním MATERIALIZED vynutit samostatný výpočet dotazu WITH

Takže:

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

Obvykle by nic z toho nemělo být nutné, pokud je váš DB server správně nakonfigurován a statistiky sloupců jsou aktuální. Existují však rohové případy s nerovnoměrným rozložením dat ...




  1. Typy v MySQL:BigInt (20) vs Int (20)

  2. Jak mohu efektivně vybrat předchozí nenulovou hodnotu?

  3. Funkce NANVL() v Oracle

  4. Jak získat informace o chybě kompilace v Oracle/TOAD