Làm thế nào để sử dụng các chỉ mục với sự tham gia bên trong Postgis?


8

Tôi có 2 bộ điểm trong 2 bảng riêng biệt. Table_a có 100k điểm và Table_b có 300k điểm. Tôi cố gắng tìm các điểm gần nhất trong mối quan hệ tìm cho tôi bất kỳ điểm nào từ bảng_b trong phạm vi 50 mét từ tabla_a. Sau cột tính toán đó, hãy nhóm chúng theo cột table_a a_id và trả về giá trị cao nhất.

Tôi đã viết một truy vấn sau đây đáp ứng criteira này

SELECT DISTINCT ON (a_id) *
FROM (
       SELECT
         table_b.b_id,
         table_b.height - st_3ddistance(table_b.geom, table_a.geom) fall,
         table_b.geom,
         table_a.a_id
       FROM table_a
         INNER JOIN table_b ON _st_3ddwithin(table_a.geom, table_b.geom, 50)) a
WHERE fall >= 0
ORDER BY a_id, fall DESC;

Tôi đã thêm các chỉ mục hình học 3d:

CREATE INDEX table_a_geom ON table_a USING GIST (geom gist_geometry_ops_nd);
CREATE INDEX table_b_geom ON table_b USING GIST (geom gist_geometry_ops_nd);

Tuy nhiên, vấn đề của tôi là tôi không thể thực hiện truy vấn để sử dụng chúng. Truy vấn kế hoạch là tiếp tục chọn quét chuỗi chậm. Tôi chạy một số thử nghiệm thay đổi _st_3ddwithin với st_3ddwithin , << - >> <50 , tạo bộ đệm 50 m và giao nhau , st_3ddistance <50 nhưng mọi người lập kế hoạch đều chọn quét theo trình tự. Có cách nào để sử dụng các chỉ mục có hiệu suất cao hơn hoặc thay đổi truy vấn để sử dụng các chỉ mục không?

Kế hoạch truy vấn của tôi:

Unique  (cost=10462593.70..10473018.43 rows=1 width=144)
  ->  Sort  (cost=10462593.70..10467806.06 rows=2084945 width=144)
        Sort Key: table_a.nmbayuid, ((table_b.height - st_3ddistance(table_b.geomgr, table_a.geom))) DESC
        ->  Nested Loop  (cost=0.00..10243762.28 rows=2084945 width=144)
              Join Filter: (_st_dwithin(table_a.geom, table_b.geomgr, '50'::double precision) AND ((table_b.height - st_3ddistance(table_b.geomgr, table_a.geom)) >= '0'::double precision))
              ->  Seq Scan on table_b  (cost=0.00..1459.47 rows=47147 width=96)
              ->  Materialize  (cost=0.00..10.97 rows=398 width=56)
                    ->  Seq Scan on table_a  (cost=0.00..8.98 rows=398 width=56)

1
Chính xác thì e_wires_mv12404 nằm trong kế hoạch truy vấn nhưng không phải là SQL? Kế hoạch truy vấn cho chỉ truy vấn bên trong trông như thế nào? Tôi đề nghị không sử dụng chức năng bắt đầu bằng _ST. Cuối cùng, bạn có thể có được hiệu suất tốt hơn khi sử dụng ST_DWithin ở dạng 2D, sử dụng 35 mét, tương đương với 50 mét từ các cạnh đối diện của khối lập phương. Khi bạn đang tìm kiếm điểm gần nhất trong vòng 50 mét, đây có thể là một ứng cử viên tốt cho việc tham gia bên và sử dụng cấu trúc ORDER BY a.geom <-> b.geom.
John Powell

1
Tôi đã có một vấn đề tương tự năm ngoái, tôi đã đào bài đăng này cho bạn , cho tôi biết nếu nó không trả lời câu hỏi của bạn?
WxGeo

2
Nếu bạn nhìn vào định nghĩa sql của các hàm bạn sẽ thấy rằng các hàm st_ như st_dwithin thực sự là một kiểm tra hộp giới hạn và một lệnh gọi đến hàm st . Đây là phần hộp giới hạn có thể sử dụng chỉ mục khi bạn gọi hàm st trực tiếp không có cách nào để cơ sở dữ liệu sử dụng chỉ mục. Bạn gọi hàm kiểm tra lại trực tiếp.
Nicklas Avén

1
Bạn có muốn tôi viết lên giải pháp tham gia bên này không, tôi nghĩ rằng nó sẽ hoạt động tốt với những gì bạn mô tả
John Powell

1
Các hàm @AndreSilva bắt đầu bằng _STlà các hàm bên trong được PostGIS gọi sau khi lọc bằng một chỉ mục. Nếu bạn gọi họ trực tiếp, chỉ mục sẽ không được sử dụng.
dbaston

Câu trả lời:


6

Thứ nhất, như đã được lưu ý trong các bình luận, dấu gạch dưới hàng đầu trước hàm ST, tức là, _ST_3DWithin sẽ dẫn đến chỉ mục không được sử dụng. Tôi không thể tìm thấy bất kỳ đề cập nào gần đây về điều này, nhưng trong các tài liệu cũ hơn nếu bạn tìm kiếm, ví dụ: _ST_Intects nó ghi:

Để tránh sử dụng chỉ mục, hãy sử dụng hàm _ST_Intersects.

EDIT: Như được làm rõ bởi @dbaston trong các bình luận, các hàm có dấu gạch dưới hàng đầu là các hàm bên trong không sử dụng chỉ mục khi được gọi và điều này tiếp tục là trường hợp (mặc dù rất khó tìm thấy trong các tài liệu).

Truy vấn của bạn có thể có thể được hưởng lợi từ cú pháp LATITH THAM GIA, vốn rất phù hợp với k vấn đề hàng xóm (kNN) gần nhất như vấn đề này.

SELECT 
   a.a_id, 
   b.b_id
   b.height - ST_3Ddistance(b.geom, a.geom) AS fall,
  FROM table_a a
     LEFT JOIN LATERAL
       (SELECT
            b_id,         
            geom,
            height        
          FROM table_b
          WHERE ST_3Ddwithin(a.geom, geom, 50)
          AND height - ST_3Ddistance(geom, a.geom) > 0
          ORDER BY height - ST_3Ddistance(b.geom, a.geom) DESC 
          LIMIT 1
        ) b ON TRUE;

Điều này cho phép bạn tìm k hình học gần nhất từ ​​bảng a (trong trường hợp này là 1, do GIỚI HẠN 1) đến bảng b, được sắp xếp theo khoảng cách 3D giữa chúng. Nó được viết bằng cách sử dụng LEFT THAM GIA, vì có thể hình dung rằng có thể có một số hình học trong bảng a không nằm trong phạm vi 50 mét của bảng b.

Các truy vấn bên cho phép bạn tham chiếu các cột từ mệnh đề TỪ trước đó, điều này làm cho nó mạnh hơn các truy vấn phụ tiêu chuẩn, xem các tài liệu .

Tôi không thể kiểm tra điều này với dữ liệu của bạn, nhưng khi tôi đã chạy các truy vấn tương tự, câu lệnh EXPLAIN cho biết việc sử dụng chỉ mục thích hợp.


Nhận xét của bạn rất hợp lý nhưng tôi không thể chấp nhận câu trả lời vì truy vấn bạn cung cấp đang thực hiện khác nhau nghĩ rằng truy vấn ban đầu. Khi tôi biệt thự trước "tôi không tìm kiếm điểm gần nhất mà là một nhóm điểm trong vòng 50 mét và sau đó tôi đang chọn một điểm có giá trị trừ cao nhất (chiều cao - ST_3Ddistance (geom, a.geom)) được nhóm bởi a_id
Losbaltica

Tôi đã sửa đổi truy vấn của bạn, vui lòng xem và thêm các cải tiến nếu cần :)
Losbaltica

1
Tôi đã sửa đổi truy vấn, thứ duy nhất còn thiếu là "chiều cao -" theo thứ tự. Bây giờ sẽ tìm thấy tất cả các điểm trong vòng 50 và trả về điểm có giá trị chiều cao cao nhất - ST_3Ddistance (b.geom, a.geom). Không cần phân biệt, vì tất cả được xử lý bởi mỗi truy vấn bên và GIỚI HẠN 1, tức là bạn sẽ chỉ nhận được giá trị giảm lớn nhất cho mỗi a_id.
John Powell

Đây có phải là làm việc như bạn mong đợi ban đầu. Liệu EXPLAIN trông có vẻ hợp lý?
John Powell

Đang làm việc như mong đợi. Hiệu năng truy vấn gần như giống nhau nhưng chi phí của truy vấn nhỏ hơn rất nhiều. EXPLAIN mới: giải thích.depesz.com/s/Js5G Tôi nghĩ rằng tôi đạt đến giới hạn tối ưu hóa truy vấn và chỉ nghĩ rằng tôi có thể làm bây giờ là điều chỉnh máy chủ hoặc cấu trúc lại các bảng / logic. Vì vậy, nó trả lời tôi câu hỏi ban đầu
Losbaltica

2

Liên kết này đến tài liệu PostGIS khuyến nghị các bước sau để đảm bảo các chỉ mục và trình lập kế hoạch truy vấn được tối ưu hóa:

  1. Đảm bảo số liệu thống kê được thu thập về số lượng và phân phối các giá trị trong một bảng, để cung cấp cho trình hoạch định truy vấn thông tin tốt hơn để đưa ra quyết định xung quanh việc sử dụng chỉ mục. VACUUM ANALYZE sẽ tính toán cả hai.

  2. Nếu việc hút bụi không giúp ích được gì, bạn có thể tạm thời buộc người lập kế hoạch sử dụng thông tin chỉ mục bằng cách sử dụng bộ enable_seqscan để tắt; chỉ huy. Bằng cách này, bạn có thể kiểm tra xem trình hoạch định có khả năng tạo kế hoạch truy vấn tăng tốc chỉ mục cho truy vấn của bạn hay không. Bạn chỉ nên sử dụng lệnh này để gỡ lỗi: nói chung, trình lập kế hoạch biết rõ hơn bạn thực hiện khi nào nên sử dụng chỉ mục. Khi bạn đã chạy truy vấn của mình, đừng quên đặt lại ENABLE_SEQSCAN để các truy vấn khác sẽ sử dụng trình lập kế hoạch như bình thường.

  3. Nếu đặt enable_seqscan thành tắt; giúp truy vấn của bạn chạy, Postgres của bạn có thể không được điều chỉnh cho phần cứng của bạn. Nếu bạn thấy trình hoạch định sai về chi phí quét tuần tự so với quét chỉ mục, hãy thử giảm giá trị của Random_page_cost trong postgresql.conf hoặc sử dụng set Random_page_cost thành 1.1;. Giá trị mặc định cho tham số là 4, hãy thử đặt thành 1 (trên SSD) hoặc 2 (trên các đĩa từ tính nhanh). Giảm giá trị làm cho trình hoạch định có xu hướng sử dụng quét Index hơn.

  4. Nếu đặt enable_seqscan thành tắt; không giúp ích cho truy vấn của bạn, có thể bạn sử dụng Postgres xây dựng chưa thể gỡ rối. Một truy vấn con với lựa chọn nội tuyến là một ví dụ - bạn cần viết lại nó để trình lập kế hoạch biểu mẫu có thể tối ưu hóa, giả sử, THAM GIA LATITH.

Vì vậy, trước tiên hãy thử các bước 1-3 trước khi viết lại truy vấn của bạn để sử dụng các chỉ mục. Nếu điều đó không làm việc, bạn có thể cố gắng sửa đổi truy vấn.

Tôi tin rằng (với khả năng tốt nhất của tôi để đánh bại SQL mà không cần chạy mã) rằng truy vấn bên dưới sẽ trả về kết quả giống hệt cho bạn, nhưng không biết liệu nó có hiệu quả hơn không.

SELECT DISTINCT on (a_id),
    table_b.b_id as b_id,
    table_b.height - st_3ddistance(table_b.geom, table_a.geom) as fall,
    table_b.geom as b_geom,
    table_a.a_id as a_id
    FROM table_a
         INNER JOIN table_b ON _st_3ddwithin(table_a.geom, table_b.geom, 50)) a
WHERE fall >= 0
ORDER BY a_id, fall DESC;

Rất thú vị sau khi thay đổi _st_3ddwithin thành st_dwithin như các bình luận khác được đề xuất và chạy VACUUM ANALYZE sau đó, kế hoạch cuối cùng cũng bắt đầu bắt được chỉ mục!
Losbaltica

0

Nếu bạn đang sử dụng Postgres 10 (hoặc mới hơn), tôi thực sự khuyên bạn nên tải dữ liệu của mình trong các bảng Song song.

Bạn có thể sẽ cần dành thời gian để điều chỉnh nó (phân vùng dữ liệu và số lượng công nhân), nhưng tôi nghĩ là đáng để nỗ lực. Về mặt lý thuyết, KNN có tính song song cao, đạt độ phức tạp thời gian không đổi, thậm chí O (1) nếu số lượng công nhân bằng với số phần tử mà phép tính KNN sẽ được tính.

Một số tài liệu tham khảo thực tế về việc tải dữ liệu và thực hiện các truy vấn được cung cấp ở đây . Ông cung cấp một số chi tiết về điều chỉnh kế hoạch (để buộc nhiều công nhân phải hành động) ở đây . Điều quan trọng cần lưu ý là các tập lệnh song song liên quan đến rất nhiều sự phối hợp nhiệm vụ, do đó ràng buộc về mặt lý thuyết cực đoan của việc cung cấp sự song song cực đoan nhất không có trong thực tế, do kết nối mạng và các đặc điểm thiết kế hệ thống khá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.