Giới hạn hàng qua chức năng không gian


9

Tôi đang cố gắng cải thiện hiệu suất cho truy vấn bên dưới. Bất kể tôi viết truy vấn như thế nào (truy vấn con trong mệnh đề TỪ, truy vấn con trong mệnh đề WHERE) postgres khăng khăng chạy tất cả ~ 570K hàng thông qua hàm ST_DWITHIN đắt tiền mặc dù chỉ có 60 hàng trong đó quận = 24. Làm cách nào tôi có thể nhận được các postgres để lọc trên quận = 24 TRƯỚC KHI chạy qua func postgis mà dường như tôi sẽ nhanh hơn và hiệu quả hơn nhiều? 700ms không phải là nguyên nhân của quá nhiều mối quan tâm nhưng khi bảng này tăng lên 10 triệu + Tôi lo ngại về hiệu suất.

Cũng cần lưu ý, p.id là khóa chính, p.zipcode là chỉ mục fk, z.county là chỉ mục fk và p.geom có ​​chỉ số GiST.

Truy vấn:

EXPLAIN ANALYZE
  SELECT count(p.id)
  FROM point AS p
  LEFT JOIN zipcode AS z
    ON p.zipcode = z.zipcode
  WHERE z.county = 24
    AND ST_DWithin(
      p.geom, 
      ST_SetSRID(ST_Point(-121.479756008715,38.563236291512),4269), 
      16090.0,
      false
    )

GIẢI THÍCH PHÂN TÍCH:

Aggregate  (cost=250851.91..250851.92 rows=1 width=4) (actual time=724.007..724.007 rows=1 loops=1)
  ->  Hash Join  (cost=152.05..250851.34 rows=228 width=4) (actual time=0.359..723.996 rows=51 loops=1)
        Hash Cond: ((p.zipcode)::text = (z.zipcode)::text)
        ->  Seq Scan on point p  (cost=0.00..250669.12 rows=7437 width=10) (actual time=0.258..723.867 rows=63 loops=1)
              Filter: (((geom)::geography && '0101000020AD10000063DF8B52B45E5EC070FB752018484340'::geography) AND ('0101000020AD10000063DF8B52B45E5EC070FB752018484340'::geography && _st_expand((geom)::geography, 16090::double precision)) AND _st_dwithin((g (...)
              Rows Removed by Filter: 557731
        ->  Hash  (cost=151.38..151.38 rows=54 width=6) (actual time=0.095..0.095 rows=54 loops=1)
              Buckets: 1024  Batches: 1  Memory Usage: 3kB
              ->  Bitmap Heap Scan on zipcode z  (cost=4.70..151.38 rows=54 width=6) (actual time=0.023..0.079 rows=54 loops=1)
                    Recheck Cond: (county = 24)
                    Heap Blocks: exact=39
                    ->  Bitmap Index Scan on fki_zipcode_county_foreign_key  (cost=0.00..4.68 rows=54 width=0) (actual time=0.016..0.016 rows=54 loops=1)
                          Index Cond: (county = 24)
Planning time: 0.504 ms
Execution time: 724.064 ms

Có thể thử thay đổi dòng "trỏ như p trái tham gia mã zip thành z" thành một điểm như "điểm khi p trái tham gia (CHỌN * TỪ mã zip WHERE zipcode.county = 24) là z"?
weiji14

Chỉ cần thử nó, kết quả tương tự. Khi tôi tự sao chép ~ 60 pointhàng trong đó quận = 24 vào một bảng mới, truy vấn chỉ mất 0,453ms so với 724 nên chắc chắn có sự khác biệt lớn.
Josh

1
Bạn nên sử dụng count(*)như một vấn đề của phong cách. Nếu idlà một pkid như bạn nói, điều NOT NULLđó có nghĩa là chúng giống nhau. Ngoại trừ count(id)có nhược điểm là bạn phải đặt câu hỏi đó nếu không idcó giá trị.
Evan Carroll

1
Tôi có thể hỏi tại sao bạn đang sử dụng một tham gia bên ngoài bên trái? Hãy thử thay đổi nó thành một tham gia bên trong ... Kết quả phải giống hệt nhau
MickyT

Nếu z.country là yếu tố giới hạn, tôi sẽ đề nghị bạn đặt điều này trước tiên trong truy vấn CTE và sau đó chỉ cần kiểm tra các kết quả đó để tìm giao điểm với điểm bạn quan tâm. Vì chỉ số không gian có lẽ ít được lựa chọn hơn quận = 24 trong trường hợp này, nên nó chỉ gây cản trở.
John Powell

Câu trả lời:


3

Bạn có thể thấy vấn đề với số lượng hàng dự kiến ​​so với số hàng thực tế. Người lập kế hoạch cho rằng có 7.437 hàng, tuy nhiên chỉ có 63. Số liệu thống kê bị tắt. Điều thú vị là, nó không sử dụng tìm kiếm chỉ mục (chỉ mục) giới hạn với DWithinbạn có thể dán kết quả của \d point. Phiên bản nào của PostGIS và PostgreSQL?

Hãy thử chạy ANALYZE point. Bạn có nhận được kế hoạch tương tự khi bạn di chuyển điều kiện lên không?

JOIN zipcode AS z
  ON p.zipcode = z.zipcode
  AND z.county = 24

Tôi đã chạy phân tích và cũng đã thử điều kiện AND mới trong ON nhưng vẫn nhận được 700ms thời gian chạy. Đây là PGQuery 9.4 và PostGIS 2.2.
Josh

2

Là một lưu ý phụ, có khả năng hợp lý rằng hành vi này được sửa đổi trong PostGIS 2.3.0 nếu bạn muốn gọi nó là một lỗi.

Từ các tài liệu trên PostgreSQL

Một số dương cho chi phí thực hiện ước tính cho hàm, tính theo đơn vị cpu_operator_cost. Nếu hàm trả về một tập hợp, đây là chi phí cho mỗi hàng được trả về. Nếu chi phí không được chỉ định, 1 đơn vị được giả định cho ngôn ngữ C và chức năng nội bộ và 100 đơn vị cho chức năng trong tất cả các ngôn ngữ khác. Các giá trị lớn hơn khiến trình hoạch định cố gắng tránh đánh giá hàm thường xuyên hơn mức cần thiết.

Vì vậy, chi phí mặc định là 1 (rất rẻ). D_Withinsử dụng chỉ số GIST rất rẻ. Nhưng, điều đó đã được tăng lên 100 (theo ủy quyền của nội bộ _ST_DWithin).

Bản thân tôi không phải là một fan hâm mộ lớn của phương pháp CTE. CTE là một hàng rào tối ưu hóa. Vì vậy, làm điều này trong một thời trang như vậy loại bỏ một số phòng tiềm năng để tối ưu hóa trong tương lai. Nếu saner mặc định sửa nó, tôi thà nâng cấp. Vào cuối ngày, chúng tôi phải hoàn thành công việc và phương pháp đó rõ ràng hiệu quả với bạn.


1

Nhờ gợi ý của John Powell, tôi đã sửa đổi truy vấn để đưa điều kiện giới hạn của quận vào truy vấn có / CTE và hiệu suất này được cải thiện khá nhiều so với 222ms so với 700. Vẫn khác xa so với .74 ms tôi nhận được khi dữ liệu ở trong đó bàn riêng. Tôi vẫn không chắc tại sao trình lập kế hoạch không giới hạn tập dữ liệu trước khi chạy qua chức năng postgis đắt tiền và tôi sẽ phải thử với các bộ dữ liệu lớn hơn khi tôi có chúng nhưng dường như đây là một giải pháp cho tình huống độc đáo này.

with points as (
   select p.id, p.geom from point p inner join zipcode z
   on p.zipcode = z.zipcode
   where county = 24
   ) 


SELECT count(points.id)
FROM points
WHERE ST_DWITHIN(points.geom, (ST_SetSRID(ST_Point(-121.479756008715,38.563236291512),4269)), 16090.0, false)

1
Chúng ta sẽ phải xem tất cả ba kế hoạch truy vấn và lược đồ cho bảng (được yêu cầu trong câu trả lời của tôi).
Evan Carroll

0

Bạn nên tạo một chỉ mục trên zipcode(county, zipcode), nó sẽ cung cấp cho bạn một chỉ mục chỉ quét trên z.

Bạn cũng có thể muốn thử nghiệm với btree_gisttiện ích mở rộng tạo point(zipcode, geom)chỉ mục hoặc point(geom, zipcode)zipcode(zipcode, county)chỉ mục.

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.