Tôi nên mong đợi PostGIS nhanh như thế nào để mã hóa địa chỉ được định dạng tốt?
Tôi đã cài đặt PostgreSQL 9.3.7 và PostGIS 2.1.7, tải dữ liệu quốc gia và tất cả dữ liệu trạng thái nhưng nhận thấy mã hóa địa lý chậm hơn nhiều so với tôi dự đoán. Tôi đã đặt kỳ vọng của mình quá cao? Tôi nhận được trung bình 3 mã địa lý cá nhân mỗi giây. Tôi cần làm khoảng 5 triệu và tôi không muốn đợi ba tuần cho việc này.
Đây là một máy ảo để xử lý ma trận R khổng lồ và tôi đã cài đặt cơ sở dữ liệu này ở bên cạnh để cấu hình có thể nới lỏng một chút. Nếu một sự thay đổi lớn trong cấu hình của VM sẽ giúp ích, tôi có thể thay đổi cấu hình.
Thông số phần cứng
Bộ nhớ: Bộ xử lý 65GB: 6
lscpu
mang lại cho tôi điều này:
# 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
Hệ điều hành là centos, uname -rv
cung cấp cho điều này:
# uname -rv
2.6.32-504.16.2.el6.x86_64 #1 SMP Wed Apr 22 06:48:29 UTC 2015
Cấu hình Postgresql
> 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"
Dựa trên đề xuất trước đây đối với các loại truy vấn, tôi upped shared_buffers
trong postgresql.conf
tập tin xuống còn khoảng 1/4 RAM có sẵn và kích thước bộ nhớ cache hiệu quả để 1/2 RAM:
shared_buffers = 16096MB
effective_cache_size = 31765MB
Tôi có installed_missing_indexes()
và (sau khi giải quyết các phần chèn trùng lặp vào một số bảng) không có bất kỳ lỗi nào.
Ví dụ SQL mã hóa địa lý # 1 (đợt) ~ thời gian trung bình là 2,8 / giây
Tôi đang theo dõi ví dụ từ http://postgis.net/docs/Geocode.html , nơi tôi tạo một bảng chứa địa chỉ cho mã địa lý, sau đó thực hiện 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";
Tôi đang sử dụng kích thước lô 1000 ở trên và nó sẽ trả về sau 337,70 giây. Nó chậm hơn một chút đối với các lô nhỏ hơn.
Ví dụ SQL mã hóa địa lý # 2 (hàng theo hàng) ~ thời gian trung bình là 1,2 / giây
Khi tôi khai thác địa chỉ của mình bằng cách thực hiện mã địa lý một lần với một câu lệnh trông như thế này (btw, ví dụ dưới đây mất 4,14 giây),
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;
chậm hơn một chút (2,5 lần trên mỗi bản ghi) nhưng tôi có thể xem xét phân phối thời gian truy vấn và thấy rằng đó là một số ít các truy vấn dài làm chậm điều này nhất (chỉ 2600 trong 5 triệu đầu tiên có thời gian tra cứu). Nghĩa là, 10% hàng đầu đang lấy trung bình khoảng 100 ms, 10% dưới cùng trung bình 3,69 giây, trong khi trung bình là 754 ms và trung bình là 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]
Những suy nghĩ khác
Nếu tôi không thể đạt được thứ tự tăng hiệu suất, tôi nghĩ rằng ít nhất tôi có thể đưa ra một phỏng đoán có giáo dục về việc dự đoán thời gian mã hóa chậm nhưng đối với tôi, tại sao các địa chỉ chậm lại dường như mất nhiều thời gian hơn. Tôi đang chạy địa chỉ gốc thông qua bước chuẩn hóa tùy chỉnh để đảm bảo địa chỉ được định dạng độc đáo trước khi geocode()
chức năng nhận được:
sql=paste0("select pprint_addy(normalize_address('",myAddress,"'))")
trong đó myAddress
một [Address], [City], [ST] [Zip]
chuỗi được biên dịch từ bảng địa chỉ người dùng từ cơ sở dữ liệu không phải postgresql.
Tôi đã thử (thất bại) để cài đặt pagc_normalize_address
tiện ích mở rộng nhưng không rõ ràng rằng điều này sẽ mang lại loại cải tiến mà tôi đang tìm kiếm.
Đã chỉnh sửa để thêm thông tin giám sát theo đề xuất
Hiệu suất
Một CPU được chốt: [chỉnh sửa, chỉ một bộ xử lý cho mỗi truy vấn, vì vậy tôi có 5 CPU không sử dụng]
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
Mẫu hoạt động của đĩa trên phân vùng dữ liệu trong khi một Proc được chốt ở mức 100%: [chỉnh sửa: chỉ có một bộ xử lý được sử dụng bởi truy vấn này]
# 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
Phân tích SQL đó
Đây là từ EXPLAIN ANALYZE
trên truy vấn đó:
"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"
Xem phân tích tốt hơn tại http://explain.depesz.com/s/vogS