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 BY
Klausel, 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_estimate
true gefunden, aber es hatte keine Wirkung.
Ich habe Zugriff auf den fremden Server, um bei Bedarf Objekte zu erstellen. Der Zeitstempelwert in der WHERE
Klausel kann beliebig sein. Es stammt nicht aus einer Liste vordefinierter Werte.
IntterraNearRealTimeUnitReflexes300sForeign
vsIntterraNearRealTimeUnitReflexes300s
undidx_incident_date_time_300
ich nehme an die 300er diejenigen , die gleichen sind, aber es könnte lohnt, wenn deridx_incident_date_time_300
Index auf dem fremden Server vorhandenAntworten:
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 optimierenrandom_page_cost
.Sie können CTE verwenden, um das GROUP BY-Verhalten zu isolieren:
quelle