Die Leistung von postgres_fdw ist langsam

12

Die folgende Abfrage für einen Fremdcode dauert ungefähr 5 Sekunden und wird in 3,2 Millionen Zeilen ausgeführt:

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 sehr unterschiedlich:

Normaler Tisch

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 BYKlausel, die nicht an den fremden Server weitergegeben wird, wenn ich EXPLAIN VERBOSE:

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

Das gibt 700 k 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 mit use_remote_estimatetrue gefunden, aber es hatte keine Wirkung.

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

J-DawG
quelle
3
Es gibt einige Pushdown-Verbesserungen in 9.6, die von Interesse sein könnten: wiki.postgresql.org/wiki/NewIn96#postgres_fdw
Jack sagt, versuchen Sie topanswers.xyz
Wenn Sie sagen, dass eine normale oder eine fremde Tabelle auf derselben Tabelle (lokal und remote) oder auf unterschiedlichen Tabellen (so wie sie lauten) ausgeführt wird, überprüfen Sie die Indizierung auf dem Remoteserver, und stellen Sie sicher, dass sie identisch sind wie Sie scheinen ganz andere Informationsquellen zu lesen IntterraNearRealTimeUnitReflexes300sForeignvs IntterraNearRealTimeUnitReflexes300sund idx_incident_date_time_300 ich nehme an die 300er diejenigen , die gleichen sind, aber es könnte lohnt, wenn der idx_incident_date_time_300Index auf dem fremden Server vorhanden
Ste Bov
2
Soweit ich weiß, werden Aggregate (COUNT) nicht auf den Remote-Server übertragen, was die lange Anforderungszeit erklären würde. Es sieht
Jerome WAGNER
@ Jerome Wagner - Awesome
J-DawG

Antworten:

7

Wenn Sie verwenden use_remote_estimate, stellen Sie sicher, dass Sie ANALYZE für die Fremdtabelle ausführen (ich sehe Schätzungen, die den zurückgegebenen ziemlich nahe kommen, wahrscheinlich haben Sie es getan). Die Pushdown-Verbesserungen sind auch in der Version <9.5 nicht verfügbar. Ich gehe auch davon aus, dass Sie auf dem Remote-Server dieselbe Tabellenstruktur haben (einschließlich der 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 ( Zeitstempelbereiche) zu erzwingen). Leider gibt es keinen sauberen Weg, um 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 Durchsuchen von Lesevorgängen). Wenn Sie eine SSD verwenden, ist es wahrscheinlich hilfreich, diese zu optimieren random_page_cost.

Sie können CTE verwenden, um das GROUP BY-Verhalten zu 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";
3manuek
quelle
1
Die Leistung war mit dem CTE gleich. Versucht allerdings die Einstellungen für random_page_cost. Vielen Dank!
J-DawG