La requête suivante sur un étranger prend environ 5 secondes pour s'exécuter sur 3,2 millions de lignes:
SELECT x."IncidentTypeCode", COUNT(x."IncidentTypeCode")
FROM "IntterraNearRealTimeUnitReflexes300sForeign" x
WHERE x."IncidentDateTime" >= '05/01/2016'
GROUP BY x."IncidentTypeCode"
ORDER BY 1;
Lorsque j'exécute la même requête sur une table normale, elle revient en 0,6 seconde. Les plans d'exécution sont assez différents:
Table normale
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
Table étrangère
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
Je pense que je paie un prix élevé pour la GROUP BY
clause, qui n'est pas transmise au serveur étranger lorsque je EXPLAIN VERBOSE
:
SELECT
"IncidentTypeCode"
FROM
PUBLIC ."IntterraNearRealTimeUnitReflexes300s"
WHERE
(
(
"IncidentDateTime" >= '2016-05-01 00:00:00' :: TIMESTAMP WITHOUT TIME ZONE
)
)
Cela renvoie 700k lignes. Y a-t-il un moyen de contourner ceci?
Hier, j'ai passé beaucoup de temps à lire cette page de documentation et j'ai pensé avoir trouvé ma réponse en définissant use_remote_estimate
true, mais cela n'a eu aucun effet.
J'ai accès au serveur étranger pour créer des objets si nécessaire. La valeur d'horodatage dans la WHERE
clause peut être n'importe quoi; il ne provient pas d'une liste de valeurs prédéfinies.
IntterraNearRealTimeUnitReflexes300sForeign
rapportIntterraNearRealTimeUnitReflexes300s
etidx_incident_date_time_300
je suppose que ceux de 300s sont les mêmes, mais il pourrait être vérifier en valeur si l'idx_incident_date_time_300
index existe sur le serveur étrangerRéponses:
Si vous utilisez
use_remote_estimate
assurez-vous d'exécuter ANALYSER la table étrangère (je vois des estimations assez proches de celles retournées, vous l'auriez probablement fait). De plus, les améliorations du menu déroulant ne sont pas disponibles dans la version <9.5. Je suppose également que vous avez la même structure de table sur le serveur distant (y compris les index). Si un bitmap est nécessaire en raison de la faible cardinalité, il n'utilisera pas l'index en raison des limitations du mécanisme de refoulement. Vous souhaiterez peut-être réduire le nombre de lignes renvoyées pour forcer une analyse d'index BTREE ( plages d'horodatage). Malheureusement, il n'existe aucun moyen propre d'éviter le SeqScan sur le serveur distant si le filtre renvoie + 10% des lignes de la table (peut varier ce pourcentage si le planificateur considère que l'analyse de la table entière est moins chère que la recherche de lectures). Si vous utilisez SSD, vous trouverez probablement utile de modifierrandom_page_cost
).Vous pouvez utiliser CTE pour isoler le comportement GROUP BY:
la source