sql >> Base de Datos >  >> RDS >> PostgreSQL

Cómo forzar la evaluación de la subconsulta antes de unirse/presionar hacia un servidor externo

Contenedor de datos extranjeros

Por lo general, las uniones o cualquier tabla derivada de subconsultas o CTE no están disponibles en el servidor externo y deben ejecutarse localmente. Es decir, todas las filas restantes después del simple WHERE La cláusula en su ejemplo debe recuperarse y procesarse localmente como observó.

Si todo lo demás falla, puede ejecutar la subconsulta SELECT id FROM lookup_table WHERE x = 5 y concatenar los resultados en la cadena de consulta.

Más convenientemente, puede automatizar esto con SQL dinámico y EXECUTE en una función PL/pgSQL. Me gusta:

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:

  • Nombre de tabla como parámetro de función de PostgreSQL

O prueba esta búsqueda en SO.

O puede usar el meta-comando \gexec en psql. Ver:

  • Filtrar los nombres de las columnas de la tabla existente para la instrucción SQL DDL

O esto podría funcionar: (El comentario dice que no funciona .)

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

Probando localmente, obtengo un plan 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)

Énfasis en negrita mío.

El parámetro $0 en el plan inspira esperanza. La matriz generada podría ser algo que Postgres pueda transmitir para usarse de forma remota. No veo un plan similar con ninguno de sus otros intentos o algunos más que probé yo mismo. ¿Puedes probar con tu fdw?

Pregunta relacionada con postgres_fdw :

  • postgres_fdw:¿es posible enviar datos a un servidor externo para unirse?

Técnica general en SQL

Esa es una historia diferente. Solo usa un CTE. Pero no espero que eso ayude con el 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 Comportamiento modificado (mejorado), de modo que las CTE se pueden insertar como subconsultas, dadas algunas condiciones previas. Pero, citando el manual:

Puede anular esa decisión especificando MATERIALIZED para forzar el cálculo separado de la consulta WITH

Entonces:

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

Por lo general, nada de esto debería ser necesario si su servidor de base de datos está configurado correctamente y las estadísticas de columna están actualizadas. Pero hay casos de esquina con distribución desigual de datos...