El rendimiento de postgres_fdw es lento

12

La siguiente consulta en un extranjero tarda unos 5 segundos en ejecutarse en 3,2 millones de filas:

SELECT x."IncidentTypeCode", COUNT(x."IncidentTypeCode") 
FROM "IntterraNearRealTimeUnitReflexes300sForeign" x 
WHERE x."IncidentDateTime" >= '05/01/2016' 
GROUP BY x."IncidentTypeCode" 
ORDER BY 1;

Cuando ejecuto la misma consulta en la tabla normal, regresa en .6 segundos. Los planes de ejecución son bastante diferentes:

Tabla normal

Sort  (cost=226861.20..226861.21 rows=4 width=4) (actual time=646.447..646.448 rows=7 loops=1) 
  Sort Key: "IncidentTypeCode" 
  Sort Method: quicksort  Memory: 25kB 
  -> HashAggregate (cost=226861.12..226861.16 rows=4 width=4) (actual  time=646.433..646.434 rows=7 loops=1)
     Group Key: "IncidentTypeCode"
     -> Bitmap Heap Scan on "IntterraNearRealTimeUnitReflexes300s" x  (cost=10597.63..223318.41 rows=708542 width=4) (actual time=74.593..342.110 rows=709376 loops=1) 
        Recheck Cond: ("IncidentDateTime" >= '2016-05-01 00:00:00'::timestamp without time zone) 
        Rows Removed by Index Recheck: 12259 
        Heap Blocks: exact=27052 lossy=26888
        -> Bitmap Index Scan on idx_incident_date_time_300  (cost=0.00..10420.49 rows=708542 width=0) (actual time=69.722..69.722 rows=709376 loops=1) 
           Index Cond: ("IncidentDateTime" >= '2016-05-01 00:00:00'::timestamp without time zone) 

Planning time: 0.165 ms 
Execution time: 646.512 ms

Tabla extranjera

Sort  (cost=241132.04..241132.05 rows=4 width=4) (actual time=4782.110..4782.112 rows=7 loops=1)   
  Sort Key: "IncidentTypeCode" 
  Sort Method: quicksort  Memory: 25kB
  -> HashAggregate  (cost=241131.96..241132.00 rows=4 width=4) (actual time=4782.097..4782.100 rows=7 loops=1)
     Group Key: "IncidentTypeCode"
     -> Foreign Scan on "IntterraNearRealTimeUnitReflexes300sForeign" x  (cost=10697.63..237589.25 rows=708542 width=4) (actual time=1.916..4476.946 rows=709376 loops=1) 

Planning time: 1.413 ms 
Execution time: 4782.660 ms

Creo que estoy pagando un alto precio por la GROUP BYcláusula, que no se pasa al servidor extranjero cuando EXPLAIN VERBOSE:

SELECT
    "IncidentTypeCode"
FROM
    PUBLIC ."IntterraNearRealTimeUnitReflexes300s"
WHERE
    (
        (
            "IncidentDateTime" >= '2016-05-01 00:00:00' :: TIMESTAMP WITHOUT TIME ZONE
        )
    )

Esto devuelve 700k filas. ¿Hay alguna forma de evitar esto?

Ayer pasé mucho tiempo leyendo esta página de documentación y pensé que había encontrado mi respuesta con la configuración use_remote_estimatede verdadero, pero no tuvo ningún efecto.

Tengo acceso al servidor externo para crear objetos si es necesario. El valor de la marca de tiempo en la WHEREcláusula puede ser cualquier cosa; no proviene de una lista de valores predefinidos.

J-DawG
fuente
3
Hay algunas mejoras de pushdown en 9.6 que pueden ser de interés: wiki.postgresql.org/wiki/NewIn96#postgres_fdw
Jack dice que intente topanswers.xyz
Cuando dice tabla normal frente a tabla extranjera, se está ejecutando en la misma tabla (local y remotamente) o en tablas realmente diferentes (se lee como si fueran), si son diferentes, verifique la indexación en el servidor remoto y asegúrese de que sean las mismas. como usted parece estar leyendo completamente diferentes fuentes de información IntterraNearRealTimeUnitReflexes300sForeignfrente IntterraNearRealTimeUnitReflexes300sy idx_incident_date_time_300 presumo los 300s son los mismos, pero podría ser la pena comprobar si el idx_incident_date_time_300existe índice en el servidor extranjera
Ste Bov
2
Por lo que entiendo, los agregados (COUNT) no se envían al servidor remoto, lo que explicaría el largo tiempo de solicitud. Parece que esta característica aparecerá en la página 10 - depesz.com/2016/10/25/…
Jerome WAGNER
@JeromeWAGNER - Impresionante
J-DawG

Respuestas:

7

Si usa, use_remote_estimateasegúrese de ejecutar ANALYZE la tabla extranjera (veo estimaciones bastante cercanas a las devueltas, probablemente lo haya hecho). Además, las mejoras pushdown no están disponibles en la versión <9.5. También supongo que tiene la misma estructura de tabla en el servidor remoto (incluidos los índices). Si se necesita un mapa de bits debido a la baja cardinalidad, no utilizará el índice debido a las limitaciones del mecanismo de pushdown. Es posible que desee reducir la cantidad de filas devueltas para forzar una exploración de índice BTREE ( intervalos de marca de tiempo)) Desafortunadamente, no hay una forma limpia de evitar SeqScan en el servidor remoto si el filtro devuelve + 10% de las filas de la tabla (puede variar este porcentaje si el planificador considera que escanear toda la tabla es más barato que buscar lecturas). Si está utilizando SSD, probablemente le resultará útil modificar random_page_cost).

Puede usar CTE para aislar el comportamiento GROUP BY:

WITH atable AS (
    SELECT "IncidentTypeCode"
    FROM PUBLIC ."IntterraNearRealTimeUnitReflexes300s"
    WHERE 
       ("IncidentDateTime" 
              BETWEEN '2016-05-01 00:00:00'::TIMESTAMP WITHOUT TIME ZONE 
                  AND '2016-05-02 00:00:00'::TIMESTAMP WITHOUT TIME ZONE)
)
SELECT atable."IncidentTypeCode", COUNT(atable.IncidentTypeCode) 
FROM atable
GROUP BY atable."IncidentTypeCode" 
ORDER BY atable."IncidentTypeCode";
3manuek
fuente
1
El rendimiento fue el mismo usando el CTE. Sin embargo, intentará la configuración random_page_cost. ¡Gracias!
J-DawG