Uzamsal İşlevle Satırları Sınırlama


9

Aşağıdaki sorgu için performansı artırmak için çalışıyorum. Her ne kadar ilçe = 24 sadece 60 satır olmasına rağmen sorguyu (FROM yan tümcesinde alt sorgu, WHERE yan tümcesinde alt sorgu) nasıl yazdığına bakılmaksızın postgres pahalı ST_DWITHIN işlevi aracılığıyla tüm ~ 570K satırları çalıştırmak konusunda ısrar ediyor. Bana göre çok daha hızlı ve çok daha verimli olurdu postgis func geçmeden ÖNCE ilçe = 24 filtre postgres nasıl alabilirim? 700ms çok fazla endişeye neden değil, ancak bu tablo 10M + 'ya büyüdükçe performans konusunda endişeliyim.

Ayrıca, p.id birincil anahtardır, p.zipcode bir fk dizinidir, z.county bir fk dizinidir ve p.geom bir GiST dizinine sahiptir.

Sorgu:

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
    )

AÇIKLAMA ANALİZİ:

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

Belki "p sol birleşim zip kodunu z olarak" satırını "p sol birleşim noktası olarak (SELECT * FROM WHERE zipcode.county = 24) z" olarak değiştirmeyi deneyin?
weiji14

Sadece denedim, aynı sonuçlar. pointCounty = 24 olan ~ 60 satırları tek başlarına yeni bir tabloya kopyaladığımda, sorgu 724 ile karşılaştırıldığında sadece .453ms alır, bu yüzden kesinlikle büyük bir fark vardır.
Josh

1
Bir count(*)stil meselesi olarak kullanmalısınız . Eğer iddediğiniz gibi bir Pktld olduğunu, bu kadar NOT NULLaynı olduğumuzu hangi araçlar. Dışında count(id)bu sorunun idnulllable olup olmadığını sormak zorunda dezavantajı vardır .
Evan Carroll

1
Neden sol dış birleştirme kullandığınızı sorabilir miyim? Bir iç birleşim olarak değiştirmeyi deneyin ... Sonuçlar aynı olmalıdır
MickyT

Z.country sınırlayıcı faktörse, bunu önce bir CTE sorgusuna koymanızı ve daha sonra bu sonuçları ilgi alanınızla bir kavşak için kontrol etmenizi öneririm. Bu durumda mekansal endeks muhtemelen ilçe = 24'ten daha az seçici olduğu için, sadece yoluna girmektedir.
John Powell

Yanıtlar:


3

Beklenen ve gerçek satır sayılarıyla ilgili sorunu görebilirsiniz. Planlamacı, 7.437 satır olduğunu düşünüyor, ancak sadece 63 tane var. İstatistikler kapalı. İlginç bir şekilde, bir sınırlayıcı kutu indeksi (dizin) arama kullanarak DWithinsonucu yapıştırabilirsiniz \d point. PostGIS ve PostgreSQL'in hangi sürümü var?

Koşmayı deneyin ANALYZE point. Durumu yukarı taşıdığınızda aynı planı alıyor musunuz?

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

Analiz yaptım ve yeni AND koşulunu ON'ta da denedim, ancak hala 700ms çalışma süresi alıyordum. Bu PGSQL 9.4 ve PostGIS 2.2'dir.
Josh

2

Bir yan not olarak, bir orada makul bir böcek aramak istiyorsanız bu davranış PostGIS 2.3.0 değiştirilmiş olduğu şans.

Gönderen PostgreSQL dokümanlar

Cpu_operator_cost birimi cinsinden işlev için tahmini yürütme maliyetini veren pozitif bir sayı. İşlev bir küme döndürürse, bu döndürülen satır başına maliyettir. Maliyet belirtilmezse, C dili ve dahili işlevler için 1 birim ve diğer tüm dillerdeki işlevler için 100 birim varsayılır. Daha büyük değerler, planlayıcının işlevi gereğinden daha sık değerlendirmekten kaçınmasına neden olur.

Böylece varsayılan maliyet 1 (çok ucuz) oldu. D_WithinGIST endeksi kullanmak çok ucuz. Ancak, bu 100'e yükseltildi (iç vekil tarafından _ST_DWithin).

CTE yönteminin büyük bir hayranı değilim. CTE'ler bir optimizasyon çiti. Yani bunu böyle yapmak gelecekteki optimizasyon için potansiyel alanı ortadan kaldırır. Eğer saner varsayılan düzeltmek, ben yükseltmek istiyorum. Günün sonunda işi halletmeliyiz ve bu yöntem sizin için açıkça işe yarıyor.


1

John Powell'ın ipucu sayesinde / CTE sorgusu ile ilçe sınırlama koşulunu koymak için sorguyu gözden geçirdim ve bu performans biraz daha 222ms vs 700'e çıktı. Veriler olduğunda kendi tablosu. Hala planlayıcı neden pahalı bir postgis fonksiyonu ile çalıştırmadan önce veri kümesi sınırlamak emin değilim, ve ben onları olduğunda daha büyük veri kümeleri ile denemek zorunda kalacağım ama bu şimdilik bu benzersiz duruma bir çözüm gibi görünüyor.

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
Üç sorgu planının tümünü ve tablonun şemasını (yanıtım \ d noktasında istenen) görmek zorundayız.
Evan Carroll

0

Üzerinde bir dizin oluşturmalısınız zipcode(county, zipcode), bu size sadece bir dizin taraması yapmalıdır.

Ayrıca deneme yapmak isteyebilirsiniz btree_gistya oluşturarak uzantısı point(zipcode, geom)dizin veya point(geom, zipcode)ve zipcode(zipcode, county)indeksi.

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.