Próbuję poprawić wydajność poniższego zapytania. Bez względu na to, jak piszę zapytanie (podzapytanie w klauzuli FROM, podzapytanie w klauzuli WHERE) postgres nalega na uruchomienie wszystkich ~ 570K wierszy przez kosztowną funkcję ST_DWITHIN, nawet jeśli jest tylko 60 wierszy, gdzie county = 24. Jak mogę filtrować postgres według hrabstwa = 24 PRZED uruchomieniem funcji postgis, która wydaje mi się znacznie szybsza i znacznie wydajniejsza? 700ms nie jest powodem do zbytniego niepokoju, ale kiedy ta tabela rośnie do 10M +, martwię się o wydajność.
Należy również zauważyć, p.id jest kluczem podstawowym, p.zipcode jest indeksem fk, z.county jest indeksem fk, a p.geom ma indeks GiST.
Pytanie:
EXPLAIN ANALYZE
SELECT count(p.id)
FROM point AS p
LEFT JOIN zipcode AS z
ON p.zipcode = z.zipcode
WHERE z.county = 24
AND ST_DWithin(
p.geom,
ST_SetSRID(ST_Point(-121.479756008715,38.563236291512),4269),
16090.0,
false
)
OBJAŚNIJ ANALIZĘ:
Aggregate (cost=250851.91..250851.92 rows=1 width=4) (actual time=724.007..724.007 rows=1 loops=1)
-> Hash Join (cost=152.05..250851.34 rows=228 width=4) (actual time=0.359..723.996 rows=51 loops=1)
Hash Cond: ((p.zipcode)::text = (z.zipcode)::text)
-> Seq Scan on point p (cost=0.00..250669.12 rows=7437 width=10) (actual time=0.258..723.867 rows=63 loops=1)
Filter: (((geom)::geography && '0101000020AD10000063DF8B52B45E5EC070FB752018484340'::geography) AND ('0101000020AD10000063DF8B52B45E5EC070FB752018484340'::geography && _st_expand((geom)::geography, 16090::double precision)) AND _st_dwithin((g (...)
Rows Removed by Filter: 557731
-> Hash (cost=151.38..151.38 rows=54 width=6) (actual time=0.095..0.095 rows=54 loops=1)
Buckets: 1024 Batches: 1 Memory Usage: 3kB
-> Bitmap Heap Scan on zipcode z (cost=4.70..151.38 rows=54 width=6) (actual time=0.023..0.079 rows=54 loops=1)
Recheck Cond: (county = 24)
Heap Blocks: exact=39
-> Bitmap Index Scan on fki_zipcode_county_foreign_key (cost=0.00..4.68 rows=54 width=0) (actual time=0.016..0.016 rows=54 loops=1)
Index Cond: (county = 24)
Planning time: 0.504 ms
Execution time: 724.064 ms
point
kopiuję same ~ 60 wierszy, w których county = 24, do nowej tabeli same, zapytanie zajmuje tylko 0,453 ms w porównaniu do 724, więc jest zdecydowanie duża różnica.
count(*)
ze względu na styl. Jeśli id
to pkid, jak mówisz, NOT NULL
oznacza to, że są takie same. Poza tym count(id)
ma tę wadę, że musisz zadać to pytanie, jeśli id
jest zerowe.