it-swarm.com.de

Die Leistung von postgres_fdw ist langsam

Die folgende Abfrage für einen Fremdkörper dauert ca. 5 Sekunden, um sie in 3,2 Millionen Zeilen auszuführen:

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

Wenn ich dieselbe Abfrage für eine normale Tabelle ausführe, wird sie in 0,6 Sekunden zurückgegeben. Die Ausführungspläne sind ganz anders:

Normale Tabelle

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

Ausländische Tabelle

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

Ich glaube, ich zahle einen hohen Preis für die GROUP BY - Klausel, die nicht an den fremden Server übergeben wird, wenn ich EXPLAIN VERBOSE:

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

Dies gibt 700.000 Zeilen zurück. Gibt es einen Weg, dies zu umgehen?

Ich habe gestern viel Zeit damit verbracht, diese Dokumentationsseite zu lesen, und dachte, ich hätte meine Antwort gefunden, indem ich use_remote_estimate Auf true gesetzt habe, aber es hatte keine Auswirkung.

Ich habe Zugriff auf den fremden Server, um bei Bedarf Objekte zu erstellen. Der Zeitstempelwert in der Klausel WHERE kann beliebig sein. Es stammt nicht aus einer Liste vordefinierter Werte.

12
J-DawG

Wenn du benutzt use_remote_estimate stellen Sie sicher, dass Sie ANALYSE die fremde Tabelle ausführen (ich sehe Schätzungen ziemlich nahe an der zurückgegebenen, Sie hätten es wahrscheinlich getan). Außerdem sind die Pushdown-Verbesserungen in der Version <9.5 nicht verfügbar. Ich gehe auch davon aus, dass Sie auf dem Remote-Server dieselbe Tabellenstruktur haben (einschließlich Indizes). Wenn aufgrund der geringen Kardinalität eine Bitmap benötigt wird, wird der Index aufgrund der Einschränkungen des Pushdown-Mechanismus nicht verwendet. Möglicherweise möchten Sie die Anzahl der zurückgegebenen Zeilen reduzieren, um einen BTREE-Index-Scan zu erzwingen (Zeitstempelbereiche). Leider gibt es keine saubere Möglichkeit, den SeqScan auf dem Remote-Server zu vermeiden, wenn der Filter + 10% der Zeilen der Tabelle zurückgibt (kann diesen Prozentsatz variieren, wenn der Planer der Ansicht ist, dass das Scannen der gesamten Tabelle billiger ist als das Suchen von Lesevorgängen). Wenn Sie SSD verwenden, werden Sie wahrscheinlich nützlich sein, um random_page_cost).

Mit CTE können Sie das Verhalten von GROUP BY isolieren:

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";
7
3manuek