ST_Distance không sử dụng chỉ mục cho truy vấn không gian


10

Tôi không thể chạy PostGIS 2.1 trên PostgreSQL 9.3.5 để sử dụng chỉ mục không gian ngay cả đối với các truy vấn đơn giản nhất. Các toàn bộ dữ liệu là 8 triệu điểm (count lưới dân từ đây) . Bảng được tạo như là

CREATE TABLE points (
    population DOUBLE PRECISION NOT NULL,
    location GEOGRAPHY(4326, POINT) NOT NULL
)
CREATE INDEX points_gix ON points USING GIST(location);

Các truy vấn đơn giản như họ nhận được

SELECT SUM(population)
FROM points
WHERE ST_Distance(
    location,
    ST_GeographyFromText('SRID=4326; POINT(0 0)')
) < 1000

PostgreSQL luôn sử dụng quét Seq cho nó, tôi đã thử một tập hợp con với 10000 điểm - vẫn quét Seq. Có ý kiến ​​gì không?


3
Bạn không sử dụng bất kỳ chức năng nào có thể sử dụng chỉ mục. Sử dụng st_dwithin thay thế. Sau đó, đầu tiên sẽ thực hiện quét chỉ mục.
Nicklas Avén

Hãy suy nghĩ về những gì truy vấn của bạn đang làm - tính khoảng cách từ mỗi điểm trong bảng đến một điểm cố định - và bạn sẽ hiểu tại sao không có chỉ mục nào có thể được sử dụng. Thay vào đó, hãy sử dụng một toán tử có thể sử dụng một chỉ mục, như ST_DWithin
Vince

Câu trả lời:


19

ST_Distance thực sự tính toán khoảng cách giữa tất cả các cặp điểm, do đó, không có chỉ số nào có thể được sử dụng. Vì vậy, truy vấn của bạn sẽ thực hiện quét theo trình tự và sau đó chọn những hình học nhỏ hơn khoảng cách bạn chỉ định. Bạn đang tìm ST_DWithin , sử dụng một chỉ mục.

SELECT SUM(population) FROM points 
WHERE ST_DWithin(location, ST_GeographyFromText('SRID=4326; POINT(0 0)'), 1000);

ST_Distance hữu ích hơn cho việc đặt hàng kết quả, thường được kết hợp với ORDER BY và / hoặc LIMIT, đã thu được với các truy vấn sử dụng chỉ mục.


1
Cảm ơn. Tôi thực sự nên đọc tài liệu trước khi đặt câu hỏi.
khớp thần kinh

1
Ôi! CẢM ƠN BẠN! Bạn chỉ "tăng tốc" truy vấn chậm của tôi như gấp 100 lần hoặc nhiều hơn do thay đổi st_distance thành st_dwithin. (Tôi nói "tăng tốc" vì điều này không bao giờ nên xảy ra ở nơi đầu tiên nếu tôi cẩn thận hơn)
Hendy

1
@HendyI Girls. Không có gì. Đó là một sai lầm dễ dàng để thực hiện.
John Powell

@ JohnPowellakaBarça Tôi đã thêm một tối ưu hóa khác (mặc dù rất mất mát , tôi đã thêm một câu trả lời cho trường hợp của tôi) nhưng bạn đã chỉ cho tôi đi đúng hướng, cảm ơn.
Hendy

4

Như @ JohnPowellakaBarça đã nói ST_DWithin()là cách để đi khi bạn muốn sự đúng đắn .

Tuy nhiên trong trường hợp của tôi, tôi chỉ muốn một ước tính sơ bộ nên thậm chí còn ST_DWithin()quá đắt (chi phí truy vấn) cho nhu cầu của tôi. Tôi đã sử dụng &&ST_Expand(box2d)(đừng nhầm điều này với geometryphiên bản) thay vào đó. Thí dụ:

SELECT * FROM profile
  WHERE
    address_point IS NOT NULL AND
    address_point && CAST(ST_Expand(CAST(ST_GeomFromText(:point) AS box2d), 0.5) AS geometry;

Điều rõ ràng ngay lập tức là chúng ta đang xử lý độ thay vì mét và sử dụng hộp giới hạn thay vì hình tròn trong một hình cầu. Đối với trường hợp sử dụng của tôi, điều này giảm từ 24 ms xuống chỉ còn 2 ms (cục bộ trong SSD). Tuy nhiên, đối với cơ sở dữ liệu sản xuất của tôi trong AWS RDS PostgreQuery với các kết nối đồng thời và hạn ngạch IOPS khó hào phóng (100 IOPS), ST_DWithin()truy vấn ban đầu sử dụng quá nhiều IOPS và có thể thực thi hơn 2000 ms và tệ hơn nhiều khi hạn ngạch IOPS bị cạn kiệt.

Điều này không dành cho tất cả mọi người nhưng trong trường hợp bạn có thể hy sinh một số độ chính xác cho tốc độ (hoặc để lưu IOPS), thì phương pháp này có thể dành cho bạn. Như bạn có thể thấy trong các kế hoạch truy vấn bên dưới, ST_DWithinvẫn yêu cầu Bộ lọc không gian bên trong Bitmap Heap Scan ngoài Recheck Cond, trong khi &&trên hình dạng hộp không cần Bộ lọc và chỉ sử dụng Recheck Cond.

Tôi cũng nhận thấy rằng IS NOT NULLvấn đề là không có nó sẽ bị bỏ lại với kế hoạch truy vấn tồi tệ hơn. Có vẻ như chỉ số GIST không "đủ thông minh" cho việc này. (tất nhiên là không cần thiết nếu cột của bạn NOT NULL, trong trường hợp của tôi là NULLcó thể)

Bảng 20000 hàng, ST_DWithin(geography, geography, 100000, FALSE)trên AWS RDS 512 MB RAM với 300 IOPS:

Aggregate  (cost=4.61..4.62 rows=1 width=8) (actual time=2011.358..2011.358 rows=1 loops=1)
  ->  Bitmap Heap Scan on matchprofile  (cost=2.83..4.61 rows=1 width=0) (actual time=1735.025..2010.635 rows=1974 loops=1)
        Recheck Cond: (((address_point IS NOT NULL) AND (address_point && '0101000020E6100000744694F606E75A40D49AE61DA7A81BC0'::geography)) OR ((hometown_point IS NOT NULL) AND (hometown_point && '0101000020E6100000744694F606E75A40D49AE61DA7A81BC0'::geography)))
        Filter: (((status)::text = 'ACTIVE'::text) AND ((gender)::text = 'MALE'::text) AND (((address_point IS NOT NULL) AND (address_point && '0101000020E6100000744694F606E75A40D49AE61DA7A81BC0'::geography) AND ('0101000020E6100000744694F606E75A40D49AE61DA7A81BC0'::geography && _st_expand(address_point, '100000'::double precision)) AND _st_dwithin(address_point, '0101000020E6100000744694F606E75A40D49AE61DA7A81BC0'::geography, '100000'::double precision, false)) OR ((hometown_point IS NOT NULL) AND (hometown_point && '0101000020E6100000744694F606E75A40D49AE61DA7A81BC0'::geography) AND ('0101000020E6100000744694F606E75A40D49AE61DA7A81BC0'::geography && _st_expand(hometown_point, '100000'::double precision)) AND _st_dwithin(hometown_point, '0101000020E6100000744694F606E75A40D49AE61DA7A81BC0'::geography, '100000'::double precision, false))))
        Rows Removed by Filter: 3323
        Heap Blocks: exact=7014
        ->  BitmapOr  (cost=2.83..2.83 rows=1 width=0) (actual time=1716.425..1716.425 rows=0 loops=1)
              ->  Bitmap Index Scan on ik_matchprofile_address_point  (cost=0.00..1.42 rows=1 width=0) (actual time=1167.698..1167.698 rows=16086 loops=1)
                    Index Cond: ((address_point IS NOT NULL) AND (address_point && '0101000020E6100000744694F606E75A40D49AE61DA7A81BC0'::geography))
              ->  Bitmap Index Scan on ik_matchprofile_hometown_point  (cost=0.00..1.42 rows=1 width=0) (actual time=548.723..548.723 rows=7846 loops=1)
                    Index Cond: ((hometown_point IS NOT NULL) AND (hometown_point && '0101000020E6100000744694F606E75A40D49AE61DA7A81BC0'::geography))
Planning time: 47.366 ms
Execution time: 2011.429 ms

Bảng 20000 hàng &&ST_Expand(box2d)trên RAM AWS RDS 512 MB với 300 IOPS:

Aggregate  (cost=3.85..3.86 rows=1 width=8) (actual time=584.346..584.346 rows=1 loops=1)
  ->  Bitmap Heap Scan on matchprofile  (cost=2.83..3.85 rows=1 width=0) (actual time=555.048..584.083 rows=1154 loops=1)
        Recheck Cond: (((address_point IS NOT NULL) AND (address_point && '0103000020E61000000100000005000000744694F606C75A40D49AE61DA7A81DC0744694F606C75A40D49AE61DA7A819C0744694F606075B40D49AE61DA7A819C0744694F606075B40D49AE61DA7A81DC0744694F606C75A40D49AE61DA7A81DC0'::geography)) OR ((hometown_point IS NOT NULL) AND (hometown_point && '0103000020E61000000100000005000000744694F606C75A40D49AE61DA7A81DC0744694F606C75A40D49AE61DA7A819C0744694F606075B40D49AE61DA7A819C0744694F606075B40D49AE61DA7A81DC0744694F606C75A40D49AE61DA7A81DC0'::geography)))
        Filter: (((status)::text = 'ACTIVE'::text) AND ((gender)::text = 'MALE'::text))
        Rows Removed by Filter: 555
        Heap Blocks: exact=3812
        ->  BitmapOr  (cost=2.83..2.83 rows=1 width=0) (actual time=553.091..553.091 rows=0 loops=1)
              ->  Bitmap Index Scan on ik_matchprofile_address_point  (cost=0.00..1.42 rows=1 width=0) (actual time=413.074..413.074 rows=4850 loops=1)
                    Index Cond: ((address_point IS NOT NULL) AND (address_point && '0103000020E61000000100000005000000744694F606C75A40D49AE61DA7A81DC0744694F606C75A40D49AE61DA7A819C0744694F606075B40D49AE61DA7A819C0744694F606075B40D49AE61DA7A81DC0744694F606C75A40D49AE61DA7A81DC0'::geography))
              ->  Bitmap Index Scan on ik_matchprofile_hometown_point  (cost=0.00..1.42 rows=1 width=0) (actual time=140.014..140.014 rows=3100 loops=1)
                    Index Cond: ((hometown_point IS NOT NULL) AND (hometown_point && '0103000020E61000000100000005000000744694F606C75A40D49AE61DA7A81DC0744694F606C75A40D49AE61DA7A819C0744694F606075B40D49AE61DA7A819C0744694F606075B40D49AE61DA7A81DC0744694F606C75A40D49AE61DA7A81DC0'::geography))
Planning time: 0.673 ms
Execution time: 584.386 ms

Một lần nữa với truy vấn đơn giản hơn:

Bảng 20000 hàng, ST_DWithin(geography, geography, 100000, FALSE)trên AWS RDS 512 MB RAM với 300 IOPS:

Aggregate  (cost=4.60..4.61 rows=1 width=8) (actual time=36.448..36.448 rows=1 loops=1)
  ->  Bitmap Heap Scan on matchprofile  (cost=2.83..4.60 rows=1 width=0) (actual time=7.694..35.545 rows=2982 loops=1)
        Recheck Cond: (((address_point IS NOT NULL) AND (address_point && '0101000020E6100000744694F606E75A40D49AE61DA7A81BC0'::geography)) OR ((hometown_point IS NOT NULL) AND (hometown_point && '0101000020E6100000744694F606E75A40D49AE61DA7A81BC0'::geography)))
        Filter: (((address_point IS NOT NULL) AND (address_point && '0101000020E6100000744694F606E75A40D49AE61DA7A81BC0'::geography) AND ('0101000020E6100000744694F606E75A40D49AE61DA7A81BC0'::geography && _st_expand(address_point, '100000'::double precision)) AND _st_dwithin(address_point, '0101000020E6100000744694F606E75A40D49AE61DA7A81BC0'::geography, '100000'::double precision, true)) OR ((hometown_point IS NOT NULL) AND (hometown_point && '0101000020E6100000744694F606E75A40D49AE61DA7A81BC0'::geography) AND ('0101000020E6100000744694F606E75A40D49AE61DA7A81BC0'::geography && _st_expand(hometown_point, '100000'::double precision)) AND _st_dwithin(hometown_point, '0101000020E6100000744694F606E75A40D49AE61DA7A81BC0'::geography, '100000'::double precision, true)))
        Rows Removed by Filter: 2322
        Heap Blocks: exact=2947
        ->  BitmapOr  (cost=2.83..2.83 rows=1 width=0) (actual time=7.197..7.197 rows=0 loops=1)
              ->  Bitmap Index Scan on ik_matchprofile_address_point  (cost=0.00..1.41 rows=1 width=0) (actual time=5.265..5.265 rows=5680 loops=1)
                    Index Cond: ((address_point IS NOT NULL) AND (address_point && '0101000020E6100000744694F606E75A40D49AE61DA7A81BC0'::geography))
              ->  Bitmap Index Scan on ik_matchprofile_hometown_point  (cost=0.00..1.41 rows=1 width=0) (actual time=1.930..1.930 rows=2743 loops=1)
                    Index Cond: ((hometown_point IS NOT NULL) AND (hometown_point && '0101000020E6100000744694F606E75A40D49AE61DA7A81BC0'::geography))
Planning time: 0.479 ms
Execution time: 36.512 ms

Bảng 20000 hàng &&ST_Expand(box2d)trên RAM AWS RDS 512 MB với 300 IOPS:

Aggregate  (cost=3.84..3.85 rows=1 width=8) (actual time=6.263..6.264 rows=1 loops=1)
  ->  Bitmap Heap Scan on matchprofile  (cost=2.83..3.84 rows=1 width=0) (actual time=4.295..5.864 rows=1711 loops=1)
        Recheck Cond: (((address_point IS NOT NULL) AND (address_point && '0103000020E61000000100000005000000744694F606C75A40D49AE61DA7A81DC0744694F606C75A40D49AE61DA7A819C0744694F606075B40D49AE61DA7A819C0744694F606075B40D49AE61DA7A81DC0744694F606C75A40D49AE61DA7A81DC0'::geography)) OR ((hometown_point IS NOT NULL) AND (hometown_point && '0103000020E61000000100000005000000744694F606C75A40D49AE61DA7A81DC0744694F606C75A40D49AE61DA7A819C0744694F606075B40D49AE61DA7A819C0744694F606075B40D49AE61DA7A81DC0744694F606C75A40D49AE61DA7A81DC0'::geography)))
        Heap Blocks: exact=1419
        ->  BitmapOr  (cost=2.83..2.83 rows=1 width=0) (actual time=4.122..4.122 rows=0 loops=1)
              ->  Bitmap Index Scan on ik_matchprofile_address_point  (cost=0.00..1.41 rows=1 width=0) (actual time=3.018..3.018 rows=1693 loops=1)
                    Index Cond: ((address_point IS NOT NULL) AND (address_point && '0103000020E61000000100000005000000744694F606C75A40D49AE61DA7A81DC0744694F606C75A40D49AE61DA7A819C0744694F606075B40D49AE61DA7A819C0744694F606075B40D49AE61DA7A81DC0744694F606C75A40D49AE61DA7A81DC0'::geography))
              ->  Bitmap Index Scan on ik_matchprofile_hometown_point  (cost=0.00..1.41 rows=1 width=0) (actual time=1.102..1.102 rows=980 loops=1)
                    Index Cond: ((hometown_point IS NOT NULL) AND (hometown_point && '0103000020E61000000100000005000000744694F606C75A40D49AE61DA7A81DC0744694F606C75A40D49AE61DA7A819C0744694F606075B40D49AE61DA7A819C0744694F606075B40D49AE61DA7A81DC0744694F606C75A40D49AE61DA7A81DC0'::geography))
Planning time: 0.399 ms
Execution time: 6.306 ms

1
Tốt viết lên và thú vị.
John Powell
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.