ST_Distance, uzamsal sorgu için dizin kullanmıyor


10

En basit sorgular için bile uzamsal bir dizin kullanmak için PostGIS 2.1 PostgreSQL 9.3.5 üzerinde çalışamıyor. Bütün veri kümesi (buradan nüfus sayımı ızgara) 8000000 puandır . Tablo şu şekilde oluşturulur

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

Sorgular aldıkları kadar basit

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

PostgreSQL her zaman bunun için Seq taramasını kullanır, 10000 puanlık bir alt kümeyi denedim - hala Seq taraması. Herhangi bir fikir?


3
Dizini kullanabilen hiçbir işlev kullanmazsınız. Bunun yerine st_dwithin kullanın. Ardından, işlev önce bir dizin taraması yapar.
Nicklas Avén

Hesaplamak mesafe her noktadan bir tabloda sabit noktaya - - sorgu ne yaptığını düşünün ve hiçbir endeks anlayacaksınız olabilir kullanılabilir. Bunun yerine ST_DWithin gibi bir dizin, kullanabileceğiniz bir operatörünü kullanmak
Vince

Yanıtlar:


19

ST_Distance aslında tüm nokta çiftleri arasındaki mesafeyi hesaplar, böylece hiçbir indeks kullanılamaz. Böylece sorgunuz bir dizi taraması yapar ve daha sonra belirttiğiniz mesafeden daha az olan geometrileri seçer. Bir indeks kullanan ST_DWithin'i arıyorsunuz .

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

ST_Distance, genellikle bir dizin kullanan sorgular ile elde edilen ORDER BY ve / veya LIMIT ile birlikte sonuçların sıralanması için daha kullanışlıdır.


1
Teşekkürler. Soru sormadan önce gerçekten belgeleri okumalıyım.
sinaps

1
VAOV! TEŞEKKÜR EDERİM! St_distance'ı st_dwithin olarak değiştirdiğim için 100x kat veya daha fazla gibi yavaş sorgumu "hızlandırdınız". (Ben "hızlandırılmış" diyorum çünkü bu daha dikkatli olsaydım ilk etapta hiç olmamalıydı)
Hendy Irawan

1
@HendyIrawan. Rica ederim. Yapması kolay bir hatadır.
John Powell

@ JohnPowellakaBarça Başka bir optimizasyon ekledim (her ne kadar çok kayıplı olsa da , davam için bir cevap ekledim) ama beni doğru yöne yönlendirdiniz, teşekkürler.
Hendy Irawan

4

@ JohnPowellakaBarça'nın dediği gibi ST_DWithin(), doğruluk istediğinizde gideceğiniz yol budur .

Ancak benim durumumda sadece kaba bir tahmin istiyorum bu yüzden bile ST_DWithin()benim ihtiyaçları için çok pahalı (sorgu maliyetinde). Bunun yerine kullandım &&ve ST_Expand(box2d)(bu geometrysürümle karıştırmayın). Misal:

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;

Hemen belli olacak olan şey, metreler yerine derecelerle uğraştığımız ve bir küredeki daire yerine sınırlayıcı kutu kullandığımızdır. Benim kullanım durumum için, bu 24 ms'den sadece 2 ms'ye (yerel olarak SSD'de) kısalır. Ancak, eşzamanlı bağlantılar ve neredeyse cömert IOPS kotaları (100 IOPS) içeren AWS RDS PostgreSQL'deki üretim veritabanım için, orijinal ST_DWithin()sorgu çok fazla IOPS harcıyor ve IOPS kotası tükendiğinde 2000 ms'den fazla ve daha kötü bir şekilde çalışabiliyor .

Bu herkes için değildir, ancak hız için (veya IOPS'u kurtarmak için) bir miktar doğruluktan ödün vermeniz durumunda, bu yaklaşım sizin için olabilir. Aşağıdaki sorgu planlarında da görebileceğiniz gibi, ST_DWithinhala Recheck Cond'a ek olarak Bitmap Yığın Taraması içinde bir uzamsal Filtre gerektirirken &&, bir kutu geometrisinde bir Filtre gerekmiyor ve sadece Recheck Cond kullanıyor.

Ben de IS NOT NULLönemli olduğunu fark ettim , onsuz daha kötü sorgu planı ile kalacak. GIST endeksi bunun için "yeterince akıllı" görünmüyor. (tabii ki sütununuz gerekli değilse NOT NULL, benim durumumda NULLmümkün)

20000 sıralı masa, ST_DWithin(geography, geography, 100000, FALSE)300 IOPS ile AWS RDS 512 MB RAM'de:

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

20000 satır tablosu &&ve ST_Expand(box2d)300 IOPS ile AWS RDS 512 MB RAM'de:

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

Daha basit bir sorgu ile:

20000 sıralı masa, ST_DWithin(geography, geography, 100000, FALSE)300 IOPS ile AWS RDS 512 MB RAM'de:

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

20000 satır tablosu &&ve ST_Expand(box2d)300 IOPS ile AWS RDS 512 MB RAM'de:

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
İyi yazma ve ilginç.
John Powell
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.