Có được tốc độ như ArcGIS trong Postgis


62

Tôi đã sử dụng Postgis 2.0 được 3/4 năm nay và trong khi tôi thực sự thích sử dụng nó, thời gian xử lý truy vấn quá mức đã khiến nó về cơ bản không thể sử dụng được cho trường hợp sử dụng của tôi.

Tôi có xu hướng xử lý địa lý nặng trên các bộ dữ liệu thành phố thường có hàng trăm ngàn đa dữ liệu. Các đa giác này đôi khi có hình dạng rất bất thường và có thể thay đổi từ 4 điểm đến 78.000 điểm trên mỗi đa tuyến.

Ví dụ: khi tôi giao một tập dữ liệu bưu kiện với 329.152 đa dữ liệu với bộ dữ liệu quyền hạn có chứa 525 đa dữ liệu, tôi nhận được các số liệu thống kê sau về tổng thời gian sử dụng:

ArcGIS 10.0 (on same host with windows 7 OS): 3 minutes
Postgis:56 minutes (not including geometry pre-processing queries)

Nói cách khác, cần thêm 1500% thời gian để thực hiện giao lộ này trong Postgis so với ArcGIS - và đây là một trong những truy vấn đơn giản hơn của tôi!

Một trong những lý do ArcGIS được cho là chạy nhanh hơn là do các chỉ số tốt hơn. Một số lập trình viên gần đây đã tìm ra cách các chỉ mục này hoạt động và tôi tự hỏi liệu có ai biết cách xây dựng các chỉ mục này trong Postgis (hoặc xây dựng các bảng có thể bắt chước các chỉ mục). Có lẽ điều này sẽ giải quyết hầu hết các vấn đề tốc độ trong Postgis. Tôi chỉ có thể hy vọng phải có một số cách, đặc biệt là vì ArcGIS chỉ có thể sử dụng 4 GB RAM trong khi tôi có thể sử dụng gấp 4 lần so với máy chủ postgis của mình!

Tất nhiên có nhiều lý do postgis có thể chạy chậm, vì vậy tôi sẽ cung cấp một phiên bản chi tiết về thông số kỹ thuật hệ thống của tôi:

Machine: Dell XPS 8300 
Processor: i7-2600 CPU @ 3.40 GHz 3.40 GHz 
Memory: Total Memory 16.0 GB (10.0 GB on virtual machine)

Platform: Ubuntu Server 12.04 Virtual Box VM

Potgres Version: 9.1.4
Postgis Version: POSTGIS="2.0.1 r9979" GEOS="3.3.5-CAPI-1.7.5" PROJ="Rel. 4.8.0, 6 March 2012" GDAL="GDAL 1.9.1, released 2012/05/15" LIBXML="2.7.8" LIBJSON="UNKNOWN" TOPOLOGY RASTER

Tôi cũng nêu chi tiết toàn bộ quá trình cài đặt mà tôi đã sử dụng để thiết lập các postgis bao gồm cả việc tạo VM .

Tôi cũng đã tăng bộ nhớ chia sẻ từ 24MB mặc định lên 6 GB trong tệp conf và chạy các lệnh sau để cho phép postgres chạy:

sudo sysctl -w kernel.shmmax=7516192768 (I know this setting is deleted every time you restart the OS)
sudo /etc/init.d/postgresql restart

Theo như tôi có thể nói điều này hoàn toàn không có gì đáng chú ý về hiệu suất.

Dưới đây là các liên kết đến dữ liệu tôi đã sử dụng cho bài kiểm tra này:

  1. Bưu kiện: tcad_parcels_06142012.shp.zip từ Thành phố Austin, TX
  2. Thẩm quyền: Ranh giới tài phán từ Thành phố Austin, TX

Dưới đây là các bước tôi đã thực hiện để xử lý dữ liệu:

ArcGIS

  1. Thêm bộ dữ liệu vào ArcMap
  2. Đặt hệ tọa độ cho chân texas trung tâm (srid 2277)
  3. Sử dụng công cụ giao lộ từ menu thả xuống

Hậu kỳ

Nhập bưu kiện bằng cách sử dụng:

shp2pgsql -c -s 2277 -D -i -I -W UTF-8 "tcad_parcels_06142012.shp" "public"."tcad_parcels_06142012" |psql -d postgis_testing -U postgres -h local_ip -p 5432

Nhập thẩm quyền sử dụng:

shp2pgsql -c -s 2277 -D -i -I -W UTF-8 "jurisdictions.shp" "public"."jurisdictions" |psql -d postgis_testing -U postgres -h local_ip -p 5432

Làm sạch hình học không hợp lệ trong bưu kiện:

DROP TABLE IF EXISTS valid_parcels;
CREATE TABLE valid_parcels(
  gid serial PRIMARY KEY,
  orig_gid integer,
  geom geometry(multipolygon,2277)
);
CREATE INDEX ON valid_parcels USING gist (geom);
INSERT INTO valid_parcels(orig_gid,geom)
  SELECT 
    gid 
    orig_gid,
    st_multi(st_makevalid(geom)) 
  FROM 
    tcad_parcels_06142012;
CLUSTER valid_parcels USING valid_parcels_geom_idx;

Làm sạch hình học không hợp lệ trong khu vực tài phán:

DROP TABLE IF EXISTS valid_jurisdictions;
CREATE TABLE valid_jurisdictions(
  gid serial PRIMARY KEY,
  orig_gid integer,
  geom geometry(multipolygon,2277)
);
CREATE INDEX ON valid_jurisdictions USING gist (geom);
INSERT INTO valid_jurisdictions(orig_gid,geom)
  SELECT 
    gid 
    orig_gid,
    st_multi(st_makevalid(geom)) 
  FROM 
    jurisdictions;
CLUSTER valid_jurisdictions USING valid_jurisdictions_geom_idx;

Chạy cụm:

cluster;

Chạy phân tích chân không:

vacuum analyze;

Thực hiện giao cắt trên các bảng được làm sạch:

CREATE TABLE parcel_jurisdictions(
  gid serial primary key,
  parcel_gid integer,
  jurisdiction_gid integer,
  isect_geom geometry(multipolygon,2277)
);
CREATE INDEX ON parcel_jurisdictions using gist (isect_geom);

INSERT INTO parcel_jurisdictions(parcel_gid,jurisdiction_gid,isect_geom)
  SELECT
    a.orig_gid parcel_gid,
    b.orig_gid jurisdiction_gid,
    st_multi(st_intersection(a.geom,b.geom))
  FROM
    valid_parcels a, valid_jurisdictions b
  WHERE
    st_intersects(a.geom,b.geom);

Giải thích Phân tích truy vấn giao lộ:

Total runtime: 3446860.731 ms
        Index Cond: (geom && b.geom)
  ->  Index Scan using valid_parcels_geom_idx on valid_parcels a  (cost=0.00..11.66 rows=2 width=1592) (actual time=0.030..4.596 rows=1366 loops=525)
  ->  Seq Scan on valid_jurisdictions b  (cost=0.00..113.25 rows=525 width=22621) (actual time=0.009..0.755 rows=525 loops=1)
Nested Loop  (cost=0.00..61428.74 rows=217501 width=24213) (actual time=2.625..3445946.889 rows=329152 loops=1)
  Join Filter: _st_intersects(a.geom, b.geom)

Từ tất cả những gì tôi đã đọc, truy vấn giao lộ của tôi rất hiệu quả và tôi hoàn toàn không biết mình đang làm gì sai để truy vấn mất 56 phút trên hình học sạch!


2
Đây là một thành ngữ phổ biến trong PostGIS để thêm kiểm tra giao lộ hộp giới hạn để tăng tốc mọi thứ. Hãy thử thêm 'AND a.geom && b.geom' vào mệnh đề WHERE của bạn và xem mức độ khác biệt của nó.
Sean

2
st_intersects () bao gồm một truy vấn hộp giới hạn trước khi thực hiện bất kỳ kiểm tra giao cắt nào trong postgis 2.x rất tiếc là sẽ không tiết kiệm bất kỳ lúc nào.
THX1138

1
Bạn có thể chạy truy vấn của mình bằng EXPLAIN ANALYZE và đăng kết quả không
Nathan W

1
bạn cũng nên lưu ý rằng bạn đang chạy các bộ dữ liệu khác nhau trên postgis vs arcgis vì bạn nói rằng bạn không làm cho chúng hợp lệ để được chấp nhận vy postgis.
Nicklas Avén

2
Có thể có được các bộ dữ liệu để xem nó?
Nicklas Avén

Câu trả lời:


87

Phương pháp khác nhau. Biết rằng cơn đau nằm trong ST_Intersection, và các thử nghiệm đúng / sai rất nhanh, cố gắng giảm thiểu lượng hình học đi qua giao lộ có thể tăng tốc mọi thứ. Ví dụ, các bưu kiện hoàn toàn nằm trong khu vực tài phán không cần phải cắt bớt, nhưng ST_Intersection có thể vẫn sẽ gặp rắc rối khi xây dựng một phần của lớp phủ giao lộ trước khi nhận ra rằng nó không phải tạo ra bất kỳ hình học mới nào. Vậy đây

INSERT INTO parcel_jurisdictions(parcel_gid,jurisdiction_gid,isect_geom)
SELECT
  a.orig_gid AS parcel_gid,
  b.orig_gid AS jurisdiction_gid,

  st_multi(st_intersection(a.geom,b.geom)) AS geom
FROM
  valid_parcels a, valid_jurisdictions b
WHERE
  st_intersects(a.geom, b.geom) and not st_within(a.geom, b.geom)
UNION ALL
SELECT
  a.orig_gid AS parcel_gid,
  b.orig_gid AS jurisdiction_gid,
  a.geom AS geom
FROM
  valid_parcels a, valid_jurisdictions b
WHERE
  st_within(a.geom, b.geom);

Hoặc thậm chí terser

INSERT INTO parcel_jurisdictions(parcel_gid,jurisdiction_gid,isect_geom)
SELECT
  a.orig_gid AS parcel_gid,
  b.orig_gid AS jurisdiction_gid,
  CASE 
     WHEN ST_Within(a.geom,b.geom) 
     THEN a.geom
     ELSE ST_Multi(ST_Intersection(a.geom,b.geom)) 
  END AS geom
FROM valid_parcels a
JOIN valid_jurisdictions b
ON ST_Intersects(a.geom, b.geom)

Thậm chí có thể nhanh hơn với UNION.


13
Cảm ơn đã đưa tôi xuống, 3,63 phút! Tôi sẽ không bao giờ nghĩ rằng một công đoàn sẽ nhanh hơn. Câu trả lời này thực sự sẽ khiến tôi suy nghĩ lại về cách tôi thực hiện các truy vấn từ bây giờ.
THX1138

2
Điều này là rất mát mẻ. Tôi đã có một trường hợp tại nơi làm việc trong đó truy vấn st_intersection của tôi mất 30 phút + và bây giờ tôi biết làm thế nào tôi có thể tránh điều đó :)
Nathan W

1
Câu hỏi này khiến tôi học Postgis! Hôm nay tôi sẽ ngủ ngon khi thấy Postgis kề vai sát cánh với Arcgis :-)
vinayan

2
Thêm một cải tiến nữa từ Martin Davis, bạn có thể nội tuyến "vào hay ra?" đặt câu hỏi vào CHỌN bằng cách sử dụng câu lệnh CASE và tránh UNION theo cách đó.
Paul Ramsey

2
UNIONloại bỏ các hàng trùng lặp khỏi hai truy vấn, nhưng hai truy vấn này không thể có cùng một hàng trong tập kết quả của chúng. Vì vậy UNION ALL, bỏ qua kiểm tra trùng lặp, sẽ thích hợp ở đây. (Tôi không sử dụng UNIONnhiều như vậy, nhưng tôi thường thấy rằng trong số những lần tôi làm, tôi thường xuyên sử dụng hơn nhiều UNION ALL.)
jpmc26

4

Điều gì sẽ xảy ra nếu bạn bỏ qua "st_multi(st_intersection(a.geom,b.geom))"phần này?

Không phải truy vấn dưới đây có nghĩa là điều tương tự mà không có nó? Tôi chạy nó trên dữ liệu bạn cung cấp.

INSERT INTO parcel_jurisdictions(parcel_gid,jurisdiction_gid,isect_geom)
  SELECT
    a.orig_gid parcel_gid,
    b.orig_gid jurisdiction_gid,
    a.geom
  FROM
    valid_parcels a, valid_jurisdictions b
  WHERE
    st_intersects(a.geom,b.geom);

Cấu hình

Processor: AMD Athlon II X4 635 2.9 GHz 
Memory: 4 GB
Platform: Windows 7 Professional
Potgres Version: 8.4
Postgis Version: "POSTGIS="2.0.1 r9979" GEOS="3.3.5-CAPI-1.7.5" PROJ="Rel. 4.8.0, 6 March 2012" GDAL="GDAL 1.9.1, released 2012/05/15" LIBXML="2.7.8" LIBJSON="UNKNOWN" TOPOLOGY RASTER"

Phân tích kết quả

"Nested Loop  (cost=0.00..7505.18 rows=217489 width=1580) (actual time=1.994..248405.616 rows=329150 loops=1)"
"  Join Filter: _st_intersects(a.geom, b.geom)"
"  ->  Seq Scan on valid_jurisdictions b  (cost=0.00..37.25 rows=525 width=22621) (actual time=0.054..1.732 rows=525 loops=1)"
"  ->  Index Scan using valid_parcels_index on valid_parcels a  (cost=0.00..11.63 rows=2 width=1576) (actual time=0.068..6.423 rows=1366 loops=525)"
"        Index Cond: (a.geom && b.geom)"
"Total runtime: 280087.497 ms"

Không, anh ta muốn các đa giác giao nhau kết quả, nhưng truy vấn của bạn rất độc đáo chứng minh rằng tất cả nỗi đau nằm ở thế hệ giao nhau, không phải trong phần kiểm tra đúng / sai nhị phân của truy vấn. Và điều đó khá được mong đợi, vì mã đúng / sai được tối ưu hóa cao trong khi thế hệ giao nhau thì không.
Paul Ramsey
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.