PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

Como forçar a avaliação da subconsulta antes de ingressar/enviar para servidor externo

Envoltório de dados estrangeiros


Normalmente, as junções ou quaisquer tabelas derivadas de subconsultas ou CTEs não estão disponíveis no servidor externo e precisam ser executadas localmente. Ou seja, todas as linhas restantes após o simples WHERE cláusula em seu exemplo deve ser recuperada e processada localmente como você observou.

Se tudo mais falhar, você pode executar a subconsulta SELECT id FROM lookup_table WHERE x = 5 e concatenar os resultados na string de consulta.

Mais convenientemente, você pode automatizar isso com SQL dinâmico e EXECUTE em uma função PL/pgSQL. Como:
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;

Relacionado:
  • Nome da tabela como parâmetro de função do PostgreSQL

Ou tente esta pesquisa no SO.

Ou você pode usar o meta-comando \gexec em psql. Ver:
  • Filtrar nomes de colunas da tabela existente para instrução SQL DDL

Ou isso pode funcionar: (O feedback diz que não funciona .)


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, recebo um plano de consulta como este:
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)

Minha ênfase em negrito.

O parâmetro $0 no plano inspira esperança. O array gerado pode ser algo que o Postgres pode passar para ser usado remotamente. Não vejo um plano semelhante em nenhuma de suas outras tentativas ou em algumas outras que eu mesmo tentei. Você pode testar com o seu fdw?

Pergunta relacionada sobre postgres_fdw :
  • postgres_fdw:é possível enviar dados para um servidor externo para ingressar?

Técnica geral em SQL


Essa é uma história diferente. Basta usar um CTE. Mas não espero que isso ajude com o 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 alterado (melhorado), para que os CTEs possam ser embutidos como subconsultas, dadas algumas pré-condições. Mas, citando o manual:

Você pode substituir essa decisão especificando MATERIALIZED para forçar o cálculo separado da consulta WITH

Então:
WITH cte AS MATERIALIZED (SELECT id FROM lookup_table WHERE x = 5)
...

Normalmente, nada disso deve ser necessário se o servidor de banco de dados estiver configurado corretamente e as estatísticas da coluna estiverem atualizadas. Mas há casos de canto com distribuição de dados desigual ...