ฉันควรคาดหวังว่า PostGIS จะจัดรูปแบบที่อยู่ในรูปแบบที่ดีได้อย่างรวดเร็วเพียงใด
ฉันได้ติดตั้ง PostgreSQL 9.3.7 และ PostGIS 2.1.7 แล้วให้โหลดข้อมูลระดับประเทศและข้อมูลสถานะทั้งหมด แต่พบว่าการเข้ารหัสภูมิศาสตร์จะช้ากว่าที่ฉันคาดไว้มาก ฉันตั้งความคาดหวังไว้สูงเกินไปหรือไม่? ฉันได้รับรหัสเฉลี่ย 3 geocodes ต่อวินาที ฉันต้องทำประมาณ 5 ล้านและฉันไม่ต้องการรอสามสัปดาห์
นี่เป็นเครื่องเสมือนจริงสำหรับการประมวลผลเมทริกซ์ R ยักษ์และฉันติดตั้งฐานข้อมูลนี้ไว้ที่ด้านข้างเพื่อให้การกำหนดค่าอาจดูโง่เล็กน้อย หากการเปลี่ยนแปลงที่สำคัญในการกำหนดค่าของ VM จะช่วยได้ฉันสามารถเปลี่ยนการกำหนดค่าได้
รายละเอียดฮาร์ดแวร์
หน่วยความจำ: โปรเซสเซอร์ 65GB: 6
lscpu
ให้สิ่งนี้กับฉัน:
# 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
ระบบปฏิบัติการคือ centos uname -rv
ให้สิ่งนี้:
# uname -rv
2.6.32-504.16.2.el6.x86_64 #1 SMP Wed Apr 22 06:48:29 UTC 2015
การกำหนดค่า 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"
ขึ้นอยู่กับข้อเสนอแนะก่อนหน้านี้กับประเภทการค้นหาเหล่านี้ผม upped shared_buffers
ในpostgresql.conf
ไฟล์ไปประมาณ 1/4 ของ RAM ที่มีขนาดและมีประสิทธิภาพในการแคช 1/2 ของ RAM:
shared_buffers = 16096MB
effective_cache_size = 31765MB
ฉันมีinstalled_missing_indexes()
และ (หลังจากแก้ไขส่วนแทรกซ้ำในบางตาราง) ไม่มีข้อผิดพลาด
ตัวอย่าง Geocoding SQL # 1 (แบทช์) ~ เวลาเฉลี่ยคือ 2.8 / วินาที
ฉันกำลังติดตามตัวอย่างจากhttp://postgis.net/docs/Geocode.htmlซึ่งให้ฉันสร้างตารางที่มีที่อยู่ไปยัง geocode แล้วสร้าง 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";
ฉันใช้ขนาดแบทช์ที่ 1,000 ขึ้นไปและมันกลับมาใน 337.70 วินาที มันช้ากว่าเล็กน้อยสำหรับแบตช์ขนาดเล็ก
ตัวอย่าง Geocoding SQL # 2 (แถวต่อแถว) ~ เวลาเฉลี่ยคือ 1.2 / วินาที
เมื่อฉันขุดลงในที่อยู่ของฉันด้วยการทำรหัสภูมิศาสตร์ทีละคำด้วยข้อความที่มีลักษณะเช่นนี้ (btw ตัวอย่างด้านล่างใช้เวลา 4.14 วินาที)
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;
มันช้ากว่าเล็กน้อย (2.5x ต่อเรคคอร์ด) แต่ฉันสามารถดูการกระจายเวลาของเคียวรีและดูว่ามันเป็นแบบสอบถามที่มีความยาวน้อยซึ่งทำให้การค้นหาช้าลงมากที่สุด (เฉพาะ 2,600 ครั้งแรกของ 5 ล้านเท่านั้นที่มีการค้นหาครั้ง) นั่นคือ 10% แรกที่ใช้ค่าเฉลี่ยประมาณ 100 มิลลิวินาทีด้านล่างเฉลี่ย 10% 3.69 วินาทีในขณะที่ค่าเฉลี่ยคือ 754 มิลลิวินาทีและค่ามัธยฐานคือ 340 มิลลิวินาที
# 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]
ความคิดอื่น ๆ
หากฉันไม่สามารถเพิ่มขนาดได้ประสิทธิภาพฉันคิดว่าอย่างน้อยฉันก็สามารถเดาการศึกษาเกี่ยวกับการทำนายเวลา geocode ที่ช้าได้ แต่มันไม่ชัดเจนสำหรับฉันว่าทำไมที่อยู่ที่ช้ากว่านั้นดูเหมือนจะใช้เวลานานกว่านั้นมาก ฉันกำลังเรียกใช้ที่อยู่เดิมผ่านขั้นตอนการทำให้เป็นมาตรฐานที่กำหนดเองเพื่อให้แน่ใจว่ามีการจัดรูปแบบไว้ก่อนgeocode()
หน้าที่จะได้รับ
sql=paste0("select pprint_addy(normalize_address('",myAddress,"'))")
ที่myAddress
เป็น[Address], [City], [ST] [Zip]
สตริงรวบรวมจากตารางอยู่ของผู้ใช้จากฐานข้อมูลที่ไม่ใช่ PostgreSQL
ฉันพยายาม (ล้มเหลว) ในการติดตั้งpagc_normalize_address
ส่วนขยาย แต่ไม่ชัดเจนว่าจะนำมาซึ่งการปรับปรุงที่ฉันกำลังมองหา
แก้ไขเพื่อเพิ่มข้อมูลการตรวจสอบตามคำแนะนำ
ประสิทธิภาพ
CPU หนึ่งถูกตรึง: [แก้ไขเพียงหนึ่งโปรเซสเซอร์ต่อการค้นหาดังนั้นฉันมี 5 CPU ที่ไม่ได้ใช้]
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
ตัวอย่างของกิจกรรมดิสก์บนพาร์ติชันข้อมูลในขณะที่หนึ่ง proc ถูกตรึงที่ 100%: [แก้ไข: เพียงหนึ่งตัวประมวลผลที่ใช้โดยแบบสอบถามนี้]
# 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
วิเคราะห์ว่า SQL
นี่คือจากEXPLAIN ANALYZE
แบบสอบถามที่:
"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"
ดูรายละเอียดที่ดีขึ้นได้ที่http://explain.depesz.com/s/vogS