O desempenho do postgres_fdw é lento

12

A consulta a seguir em um estrangeiro leva cerca de 5 segundos para executar em 3,2 milhões de linhas:

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

Quando executo a mesma consulta na tabela normal, ela retorna em 0,6 segundos. Os planos de execução são bem diferentes:

Tabela 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

Tabela estrangeira

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

Acho que estou pagando um preço alto pela GROUP BYcláusula, que não é passada para o servidor estrangeiro quando EXPLAIN VERBOSE:

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

Isso retorna 700k linhas. Existe uma maneira de contornar isso?

Ontem passei muito tempo lendo esta página de documentação e pensei ter encontrado minha resposta ao definir use_remote_estimatetrue, mas não teve efeito.

Eu tenho acesso ao servidor externo para criar objetos, se necessário. O valor do carimbo de data / hora na WHEREcláusula pode ser qualquer coisa; não vem de uma lista de valores predefinidos.

J-DawG
fonte
3
Há algumas melhorias pushdown em 9,6 que possam ser de interesse: wiki.postgresql.org/wiki/NewIn96#postgres_fdw
Jack diz tentativa topanswers.xyz
Quando você diz que tabela normal versus tabela estrangeira está executando a mesma tabela (local e remotamente) ou realmente tabelas diferentes (parece que são), se forem diferentes, verifique a indexação no servidor remoto e verifique se elas são iguais como você parece estar lendo completamente diferentes fontes de informação IntterraNearRealTimeUnitReflexes300sForeignvs IntterraNearRealTimeUnitReflexes300se idx_incident_date_time_300 presumo que os 300s aqueles são os mesmos, mas pode valer a pena verificar se o idx_incident_date_time_300índice existente no servidor estrangeira
Ste Bov
2
Pelo que entendi, os agregados (COUNT) não são enviados para o servidor remoto, o que explicaria o longo tempo de solicitação. Parece que esse recurso aparecerá na página 10 - depesz.com/2016/10/25/…
Jerome WAGNER
@JeromeWAGNER - Awesome
J-DawG

Respostas:

7

Se você tiver use_remote_estimatecerteza de executar ANALYZE na tabela estrangeira (vejo estimativas bem próximas das retornadas, provavelmente você fez isso). Além disso, as melhorias de empilhamento não estão disponíveis na versão <9.5. Também presumo que você tenha a mesma estrutura de tabela no servidor remoto (incluindo índices). Se um bitmap for necessário devido à baixa cardinalidade, ele não usará o índice devido às limitações no mecanismo de empilhamento. Convém reduzir a quantidade de linhas retornadas para forçar uma varredura de índice BTREE ( intervalos de carimbo de data / hora) Infelizmente, não há uma maneira limpa de evitar o SeqScan no servidor remoto se o filtro retornar + 10% das linhas da tabela (pode variar essa porcentagem se o planejador considerar que a varredura de toda a tabela é mais barata que a leitura solicitada). Se você estiver usando SSD, provavelmente achará útil ajustar random_page_cost).

Você pode usar o CTE para isolar o comportamento 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
fonte
1
O desempenho foi o mesmo usando o CTE. Porém, tentará as configurações de random_page_cost. Obrigado!
J-Dawg