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 BY
klauzulę, 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_estimate
na prawda, ale to nie przyniosło żadnego efektu.
Mam dostęp do obcego serwera, aby w razie potrzeby tworzyć obiekty. Wartość znacznika czasu w WHERE
klauzuli może być dowolna; nie pochodzi z listy predefiniowanych wartości.
IntterraNearRealTimeUnitReflexes300sForeign
porównaniu z,IntterraNearRealTimeUnitReflexes300s
aidx_incident_date_time_300
przypuszczam, że te 300-te są takie same, ale może warto sprawdzić, czyidx_incident_date_time_300
indeks istnieje na serwerze zagranicznymOdpowiedzi:
Jeśli używasz,
use_remote_estimate
pamię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ę poprawkirandom_page_cost
).Możesz użyć CTE do izolacji zachowania GROUP BY:
źródło