PostGIS'in iyi biçimlendirilmiş adresleri coğrafi olarak kodlamasını ne kadar hızlı beklemeliyim?
PostgreSQL 9.3.7 ve PostGIS 2.1.7'yi yükledim, ülke verilerini ve tüm eyalet verilerini yükledim ancak coğrafi kodlamanın tahmin ettiğimden çok daha yavaş olduğunu gördüm. Beklentilerimi çok yüksek mi ayarladım? Saniyede ortalama 3 ayrı coğrafi kod alıyorum. Yaklaşık 5 milyon yapmam gerekiyor ve bunun için üç hafta beklemek istemiyorum.
Bu dev R matrislerini işlemek için sanal bir makinedir ve bu veritabanını tarafa yükledim, böylece yapılandırma biraz aptalca görünebilir. VM'nin yapılandırmasında büyük bir değişiklik yardımcı olursa, yapılandırmayı değiştirebilirim.
Donanım özellikleri
Bellek: 65 GB işlemciler: 6
lscpu
bana şunu veriyor:
# 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
İşletim sistemi centos, bunu uname -rv
verir:
# uname -rv
2.6.32-504.16.2.el6.x86_64 #1 SMP Wed Apr 22 06:48:29 UTC 2015
Postgresql yapılandırması
> 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"
Bu tür sorgulara ilişkin önceki önerilere dayanarak shared_buffers
,postgresql.conf
dosyada kullanılabilir RAM'in 1 / 4'üne ve etkin önbellek boyutunun 1 / 2'si RAM'e :
shared_buffers = 16096MB
effective_cache_size = 31765MB
Sahibim installed_missing_indexes()
ve (bazı tablolara yinelenen ekler çözüldükten sonra) herhangi bir hata yoktu.
Coğrafi kodlama SQL örneği # 1 (toplu) ~ ortalama süre 2.8 / sn'dir
Bana coğrafi kod adresi içeren bir tablo oluşturmak ve daha sonra bir SQL yapıyor http://postgis.net/docs/Geocode.html gelen örneği takip ediyorum 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";
Yukarıda 1000 toplu bir boyutu kullanıyorum ve 337.70 saniye içinde döner. Daha küçük gruplar için biraz daha yavaştır.
Coğrafi kodlama SQL örneği # 2 (satır satır) ~ ortalama süre 1.2 / sn
Coğrafi kodları bir kerede böyle görünen bir ifadeyle yaparak adreslerime girdiğimde (btw, aşağıdaki örnek 4.14 saniye sürdü),
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;
biraz daha yavaş (kayıt başına 2.5x) ama sorgu sürelerinin dağılımına bakabilir ve bunun en yavaşlayan uzun sorguların az bir kısmına bakabilirim (sadece 5 milyonun ilk 2600'ü arama sürelerine sahiptir). Yani, üst% 10 ortalama 100 ms, alt% 10 ortalama 3.69 saniyedir, ortalama 754 ms ve medyan 340 ms'dir.
# 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]
Diğer düşünceler
Performansta bir büyüklük artışı siparişi alamazsam, en azından yavaş coğrafi kod zamanlarını tahmin etme konusunda eğitimli bir tahmin yapabileceğimi düşündüm, ancak yavaş adreslerin neden bu kadar uzun sürdüğü açık değil. geocode()
Fonksiyonu almadan önce güzel biçimlendirildiğinden emin olmak için orijinal adresi özel bir normalleştirme adımıyla çalıştırıyorum :
sql=paste0("select pprint_addy(normalize_address('",myAddress,"'))")
nerede myAddress
bir[Address], [City], [ST] [Zip]
postgresql olmayan bir veritabanından bir kullanıcı adres tablosundan derlenen dize.
pagc_normalize_address
Uzantıyı yüklemeyi denedim (başarısız oldum) ama bunun aradığım iyileştirmeyi getireceği açık değil.
Öneriye göre izleme bilgisi eklemek için düzenlendi
Verim
Bir CPU sabitlendi: [düzenle, sorgu başına sadece bir işlemci, bu yüzden 5 kullanılmamış CPU'm var]
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
Bir işlem% 100'de sabitlenirken veri bölümündeki disk etkinliği örneği: [değiştir: bu sorgu tarafından kullanılan yalnızca bir işlemci]
# 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
Bu SQL'i analiz edin
Bu şu EXPLAIN ANALYZE
sorgudandır:
"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"
Daha iyi dökümü http://explain.depesz.com/s/vogS adresinde görebilirsiniz.