wydajność postgres_fdw jest niska

12

Wykonanie następującego zapytania dotyczącego obcego zajmuje około 5 sekund w 3,2 milionach wierszy:

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

Kiedy wykonuję to samo zapytanie w normalnej tabeli, zwraca ono za 0,6 sekundy. Plany wykonania są zupełnie inne:

Normalny stół

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 zagraniczna

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

Myślę, że płacę wysoką cenę za GROUP BYklauzulę, która nie jest przekazywana na serwer zagraniczny, gdy EXPLAIN VERBOSE:

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

Zwraca to 700 tys. Wierszy. Czy jest na to jakiś sposób?

Wczoraj spędziłem dużo czasu czytając tę stronę dokumentacji i myślałem, że znalazłem odpowiedź z ustawieniem use_remote_estimatena prawda, ale to nie przyniosło żadnego efektu.

Mam dostęp do obcego serwera, aby w razie potrzeby tworzyć obiekty. Wartość znacznika czasu w WHEREklauzuli może być dowolna; nie pochodzi z listy predefiniowanych wartości.

J-DawG
źródło
3
W wersji 9.6 istnieje kilka ulepszeń w dół, które mogą być interesujące: wiki.postgresql.org/wiki/NewIn96#postgres_fdw
Jack mówi, że spróbuj topanswers.xyz
Kiedy mówisz, że tabela normalna vs. obca działa na tej samej tabeli (lokalnie i zdalnie) lub w rzeczywistości różnych tabelach (czyta się tak, jakby były), jeśli są różne, sprawdź indeksowanie na serwerze zdalnym, aby upewnić się, że są takie same ponieważ wydaje się, że czytasz zupełnie inne źródła informacji w IntterraNearRealTimeUnitReflexes300sForeignporównaniu z, IntterraNearRealTimeUnitReflexes300sa idx_incident_date_time_300 przypuszczam, że te 300-te są takie same, ale może warto sprawdzić, czy idx_incident_date_time_300indeks istnieje na serwerze zagranicznym
Ste Bov
2
Z tego, co rozumiem, agregaty (COUNT) nie są wypychane na zdalny serwer, co tłumaczy długi czas żądania. Wygląda na to, że ta funkcja pojawi się na stronie 10 - depesz.com/2016/10/25/…
Jerome WAGNER
@JeromeWAGNER - Awesome
J-DawG

Odpowiedzi:

7

Jeśli używasz, use_remote_estimatepamiętaj, aby uruchomić ANALIZĘ tabeli obcej (widzę oszacowania całkiem blisko z zwróconą, prawdopodobnie zrobiłbyś to). Ponadto ulepszenia przesuwania w dół nie są dostępne w wersji <9.5. Zakładam również, że masz taką samą strukturę tabeli na zdalnym serwerze (łącznie z indeksami). Jeśli bitmapa jest potrzebna z powodu niskiej kardynalności, nie będzie używać indeksu z powodu ograniczeń mechanizmu wypychania. Możesz zmniejszyć liczbę zwracanych wierszy, aby wymusić skanowanie indeksu BTREE ( zakresy znaczników czasu)). Niestety, nie ma czystego sposobu na uniknięcie SeqScan na zdalnym serwerze, jeśli filtr zwróci + 10% wierszy tabeli (może się różnić ten odsetek, jeśli planista uzna, że ​​skanowanie całej tabeli jest tańsze niż wyszukiwanie odczytów). Jeśli używasz dysku SSD, prawdopodobnie przydadzą Ci się poprawki random_page_cost).

Możesz użyć CTE do izolacji zachowania 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
źródło
1
Wydajność była taka sama przy użyciu CTE. Spróbuje jednak ustawień random_page_cost. Dzięki!
J-DawG