Quanto tempo dovrei aspettare PostGIS per geocodificare indirizzi ben formattati?
Ho installato PostgreSQL 9.3.7 e PostGIS 2.1.7, caricato i dati della nazione e tutti i dati degli stati ma ho trovato che la geocodifica è molto più lenta di quanto mi aspettassi. Ho impostato le mie aspettative troppo alte? Ricevo in media 3 singoli geocodici al secondo. Devo fare circa 5 milioni e non voglio aspettare tre settimane per questo.
Questa è una macchina virtuale per l'elaborazione di matrici R giganti e ho installato questo database sul lato in modo che la configurazione possa sembrare un po 'sciocca. Se una modifica importante nella configurazione della VM sarà di aiuto, posso modificare la configurazione.
Specifiche hardware
Memoria: processori da 65 GB: 6
lscpu
mi dà questo:
# lscpu
Architecture: x86_64
CPU op-mode(s): 32-bit, 64-bit
Byte Order: Little Endian
CPU(s): 6
On-line CPU(s) list: 0-5
Thread(s) per core: 1
Core(s) per socket: 1
Socket(s): 6
NUMA node(s): 1
Vendor ID: GenuineIntel
CPU family: 6
Model: 58
Stepping: 0
CPU MHz: 2400.000
BogoMIPS: 4800.00
Hypervisor vendor: VMware
Virtualization type: full
L1d cache: 32K
L1i cache: 32K
L2 cache: 256K
L3 cache: 30720K
NUMA node0 CPU(s): 0-5
Il sistema operativo è centos, uname -rv
dà questo:
# uname -rv
2.6.32-504.16.2.el6.x86_64 #1 SMP Wed Apr 22 06:48:29 UTC 2015
Postgresql config
> select version()
"PostgreSQL 9.3.7 on x86_64-unknown-linux-gnu, compiled by gcc (GCC) 4.4.7 20120313 (Red Hat 4.4.7-11), 64-bit"
> select PostGIS_Full_version()
POSTGIS="2.1.7 r13414" GEOS="3.4.2-CAPI-1.8.2 r3921" PROJ="Rel. 4.8.0, 6 March 2012" GDAL="GDAL 1.9.2, released 2012/10/08" LIBXML="2.7.6" LIBJSON="UNKNOWN" TOPOLOGY RASTER"
Sulla base dei precedenti suggerimenti a questi tipi di query, ho aumentato shared_buffers
il postgresql.conf
file a circa 1/4 della RAM disponibile e le dimensioni effettive della cache a 1/2 della RAM:
shared_buffers = 16096MB
effective_cache_size = 31765MB
Ho installed_missing_indexes()
e (dopo aver risolto inserti duplicati in alcune tabelle) non ho riscontrato errori.
Esempio di geocodifica SQL n. 1 (batch) ~ tempo medio di 2,8 / sec
Sto seguendo l'esempio di http://postgis.net/docs/Geocode.html , che mi ha fatto creare una tabella contenente l'indirizzo al geocode e quindi fare un SQL UPDATE
:
UPDATE addresses_to_geocode
SET (rating, longitude, latitude,geo)
= ( COALESCE((g.geom).rating,-1),
ST_X((g.geom).geomout)::numeric(8,5),
ST_Y((g.geom).geomout)::numeric(8,5),
geo )
FROM (SELECT "PatientId" as PatientId
FROM addresses_to_geocode
WHERE "rating" IS NULL ORDER BY PatientId LIMIT 1000) As a
LEFT JOIN (SELECT "PatientId" as PatientId, (geocode("Address",1)) As geom
FROM addresses_to_geocode As ag
WHERE ag.rating IS NULL ORDER BY PatientId LIMIT 1000) As g ON a.PatientId = g.PatientId
WHERE a.PatientId = addresses_to_geocode."PatientId";
Sto usando una dimensione batch di 1000 sopra e ritorna in 337.70 secondi. È un po 'più lento per i lotti più piccoli.
Esempio di geocodifica SQL n. 2 (riga per riga) ~ il tempo medio è 1,2 / sec
Quando scavo nei miei indirizzi eseguendo i geocodici uno alla volta con un'affermazione simile a questa (tra l'altro, l'esempio seguente ha richiesto 4,14 secondi),
SELECT g.rating, ST_X(g.geomout) As lon, ST_Y(g.geomout) As lat,
(addy).address As stno, (addy).streetname As street,
(addy).streettypeabbrev As styp, (addy).location As city,
(addy).stateabbrev As st,(addy).zip
FROM geocode('6433 DROMOLAND Cir NW, MASSILLON, OH 44646',1) As g;
è un po 'più lento (2,5 volte per record) ma posso vedere la distribuzione dei tempi delle query e vedere che è una minoranza di lunghe query che sta rallentando di più (solo i primi 2600 su 5 milioni hanno tempi di ricerca). Cioè, il 10% superiore sta prendendo una media di circa 100 ms, il 10% inferiore in media 3,69 secondi, mentre la media è 754 ms e la mediana è 340 ms.
# Just some interaction with the data in R
> range(lookupTimes[1:2600])
[1] 0.00 11.54
> median(lookupTimes[1:2600])
[1] 0.34
> mean(lookupTimes[1:2600])
[1] 0.7541808
> mean(sort(lookupTimes[1:2600])[1:260])
[1] 0.09984615
> mean(sort(lookupTimes[1:2600],decreasing=TRUE)[1:260])
[1] 3.691269
> hist(lookupTimes[1:2600]
Altri pensieri
Se non riesco a ottenere un ordine di grandezza in aumento delle prestazioni, ho pensato che avrei potuto almeno fare un'ipotesi plausibile sulla previsione di tempi di geocodifica lenti, ma non è ovvio per me perché gli indirizzi più lenti sembrano richiedere molto più tempo. Sto eseguendo l'indirizzo originale attraverso un passaggio di normalizzazione personalizzato per assicurarmi che sia formattato correttamente prima che la geocode()
funzione lo ottenga:
sql=paste0("select pprint_addy(normalize_address('",myAddress,"'))")
dove myAddress
è una [Address], [City], [ST] [Zip]
stringa compilata da una tabella degli indirizzi utente da un database non postgresql.
Ho provato (non riuscito) a installare l' pagc_normalize_address
estensione, ma non è chiaro che questo porterà il tipo di miglioramento che sto cercando.
Modificato per aggiungere informazioni di monitoraggio come da suggerimento
Prestazione
È collegata una CPU: [modifica, solo un processore per query, quindi ho 5 CPU inutilizzate]
top - 14:10:26 up 1 day, 3:11, 4 users, load average: 1.02, 1.01, 0.93
Tasks: 219 total, 2 running, 217 sleeping, 0 stopped, 0 zombie
Cpu(s): 15.4%us, 1.5%sy, 0.0%ni, 83.1%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st
Mem: 65056588k total, 64613476k used, 443112k free, 97096k buffers
Swap: 262139900k total, 77164k used, 262062736k free, 62745284k cached
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
3130 postgres 20 0 16.3g 8.8g 8.7g R 99.7 14.2 170:14.06 postmaster
11139 aolsson 20 0 15140 1316 932 R 0.3 0.0 0:07.78 top
11675 aolsson 20 0 135m 1836 1504 S 0.3 0.0 0:00.01 wget
1 root 20 0 19364 1064 884 S 0.0 0.0 0:01.84 init
2 root 20 0 0 0 0 S 0.0 0.0 0:00.06 kthreadd
Esempio di attività del disco sulla partizione dati mentre un proc è ancorato al 100%: [modifica: solo un processore utilizzato da questa query]
# dstat -tdD dm-3 1
----system---- --dsk/dm-3-
date/time | read writ
12-06 14:06:36|1818k 3632k
12-06 14:06:37| 0 0
12-06 14:06:38| 0 0
12-06 14:06:39| 0 0
12-06 14:06:40| 0 40k
12-06 14:06:41| 0 0
12-06 14:06:42| 0 0
12-06 14:06:43| 0 8192B
12-06 14:06:44| 0 8192B
12-06 14:06:45| 120k 60k
12-06 14:06:46| 0 0
12-06 14:06:47| 0 0
12-06 14:06:48| 0 0
12-06 14:06:49| 0 0
12-06 14:06:50| 0 28k
12-06 14:06:51| 0 96k
12-06 14:06:52| 0 0
12-06 14:06:53| 0 0
12-06 14:06:54| 0 0 ^C
Analizza quel SQL
Questo proviene EXPLAIN ANALYZE
da quella query:
"Update on addresses_to_geocode (cost=1.30..8390.04 rows=1000 width=272) (actual time=363608.219..363608.219 rows=0 loops=1)"
" -> Merge Left Join (cost=1.30..8390.04 rows=1000 width=272) (actual time=110.934..324648.385 rows=1000 loops=1)"
" Merge Cond: (a.patientid = g.patientid)"
" -> Nested Loop (cost=0.86..8336.82 rows=1000 width=184) (actual time=10.676..34.241 rows=1000 loops=1)"
" -> Subquery Scan on a (cost=0.43..54.32 rows=1000 width=32) (actual time=10.664..18.779 rows=1000 loops=1)"
" -> Limit (cost=0.43..44.32 rows=1000 width=4) (actual time=10.658..17.478 rows=1000 loops=1)"
" -> Index Scan using "addresses_to_geocode_PatientId_idx" on addresses_to_geocode addresses_to_geocode_1 (cost=0.43..195279.22 rows=4449758 width=4) (actual time=10.657..17.021 rows=1000 loops=1)"
" Filter: (rating IS NULL)"
" Rows Removed by Filter: 24110"
" -> Index Scan using "addresses_to_geocode_PatientId_idx" on addresses_to_geocode (cost=0.43..8.27 rows=1 width=152) (actual time=0.010..0.013 rows=1 loops=1000)"
" Index Cond: ("PatientId" = a.patientid)"
" -> Materialize (cost=0.43..18.22 rows=1000 width=96) (actual time=100.233..324594.558 rows=943 loops=1)"
" -> Subquery Scan on g (cost=0.43..15.72 rows=1000 width=96) (actual time=100.230..324593.435 rows=943 loops=1)"
" -> Limit (cost=0.43..5.72 rows=1000 width=42) (actual time=100.225..324591.603 rows=943 loops=1)"
" -> Index Scan using "addresses_to_geocode_PatientId_idx" on addresses_to_geocode ag (cost=0.43..23534259.93 rows=4449758000 width=42) (actual time=100.225..324591.146 rows=943 loops=1)"
" Filter: (rating IS NULL)"
" Rows Removed by Filter: 24110"
"Total runtime: 363608.316 ms"
Scopri una migliore ripartizione su http://explain.depesz.com/s/vogS