OpenStreetMap PostGIS sorgulamasını hızlandırma


12

Osmoz şemasını kullanarak bir PostGIS veritabanına (PostgreSQL 8.3 / PostGIS 1.3.3) yüklenen Hollanda için OpenStreetMap verilerine sahibim . Bu, tüm etiketlerin bir hstore alanında saklandığı anlamına gelir . Osmozun geometri alanında oluşturduğu GIST endeksine ek olarak, etiketler alanında ek bir GIST indeksi oluşturdum.

Hem uzamsal bir kısıtlama hem de etiketler alanında bir kısıtlama kullanarak sorgulamaya çalışırken, istediğimden daha yavaş olduğunu düşünüyorum. Bunun gibi bir sorgu:

SELECT n.geom,n.tags,n.tstamp,u.name FROM nodes AS n 
  INNER JOIN users AS u ON n.user_id = u.id 
  WHERE tags->'man_made'='surveillance' 
  AND ST_Within(geom, ST_GeomFromText('POLYGON((4.0 52.0,5.0 52.0,5.0 53.0,4.0 53.0,4.0 52.0))',4326));

78 kayıt döndürmek 22 saniye sürer.

Bu tabloda yaklaşık 53 milyon kayıt var.

Bunu önemli ölçüde hızlandırmanın bir yolu var mı? Ben hstore PostgreSQL 9 önemli ölçüde daha iyi uygulandığını duydum, yükseltme yardımcı olur mu?


Bu veritabanı odaklı bir soru gibi göründüğünden dba.stackexchange.com
jcolebrand

2015 Güncellemesi - PostGIS, bu soru sorulduğundan beri önemli performans iyileştirmeleri yaptı, bu nedenle PostgreSQL yükseltmesinin yanı sıra bunu da göz önünde bulundurun.
Toby Speight

Yanıtlar:


5

Yöntemlerden biri, ilgilendiğiniz etiketleri sorgulamak ve bu kayıtları yeni bir tabloya yerleştirmektir. O zaman yeni tabloyu sadece 53 milyon kayıt yerine sorgulamanız gerekir. Veritabanınızı güncel tutmaya çalışıyorsanız, OSM'den her yeni veri aldığınızda bu sorguyu çalıştırabilirsiniz.


2
Yeni bir tablo oluşturmak yerine, bunun yerine bir VIEW oluşturmayı düşünebilirsiniz, böylece "sorgu", verilerin gerçek anlamda çoğaltılmadan orijinal kaynak verilerinize canlı olarak bağlanır.
RyanKDalton

7
Bir görünüm, somutlaştırılmış bir görünüm veya eşdeğeri olmadığı sürece sorgu performansını artırmayabilir ( bu konuyla ilgili SO sorusuna bakın ). Postgresql'in doğrudan gerçekleşen görünümleri desteklediğine inanmıyorum , ancak tetikleyiciler kullanılarak uygulanabilirler.
Adam Zırh

2
Bu, şu anda kullandığım geçici çözümdür. Osmoz tablolarına yapılan bir güncellemeden sonra, çalıştırmak istediğim sorgular için optimize edilmiş birkaç tabloyu yeniden oluşturuyorum. Sadece daha iyi bir yol olması gerektiğini hissediyorum. Tetikleyiciler konusu beni ve bunları maddi görünümleri uygulamak için nasıl kullanabileceğinizi merak ediyor. @Adam Zırh, bununla ilgili bir fikir paylaşma şansın oldu mu?
mvexel

4
@mvexel Maddi görünümlerin temellerini ve PostgreSQL'de nasıl uygulanacağını anlatan bu wiki makalesine göz atın .
Adam Zırh

5

Hstore sütununuz için bir dizin oluşturmayı deneyebilirsiniz,

CREATE INDEX nodes_tags_idx ON nodes USING GIST(tags)

ve ardından ?sorguyu yalnızca bu satırlarla sınırlamak için işleci kullanın:

SELECT n.geom,n.tags,n.tstamp,u.name FROM nodes AS n 
  INNER JOIN users AS u ON n.user_id = u.id 
  WHERE tags ? 'man_made'
  AND tags->'man_made'='surveillance' 
  AND ST_Within(geom, ST_GeomFromText('POLYGON((4.0 52.0,5.0 52.0,5.0 53.0,4.0 53.0,4.0 52.0))',4326));

Teşekkürler! Bu dizini zaten oluşturdum, sadece kullanmıyordum. Yalnızca belirli işlemleri hızlandırır. PostgreSQL 8.3'te (hangisini kullanıyorum) sadece @> ve? , 9.0'da @>,?,? & ve? | .
mvexel

1
Kayıt için, ?operatör kullanarak sorgu benim sorgu için 88 saniye ile karşılaştırıldığında 48 saniye sürdü (dün 72 saniye var bilmiyorum, belki ben sorguları yaparken makine bu kez karmaşık bir şey yapıyordu). Bu yüzden hala aradığım performans değil, ancak GIST dizinlerinin hstore sütunlarında nasıl çalıştığı hakkında daha derin bir anlayış kazandım. İstediğim performansı elde etmek için materyalize bir görünüm yaratmanın diğer çözümüne devam etmem gerekecek.
mvexel

3

St_within ve _st_within işlevleri hızlarıyla bilinmemektedir. && operatörü geometri yerine bbox'ı kontrol edeceğinden yardımcı olabilir

Aşağıdakileri deneyebilirsiniz:

SELECT n.geom,n.tags,n.tstamp,u.name FROM nodes AS n 
  INNER JOIN users AS u ON n.user_id = u.id 
  WHERE tags ? 'man_made'
  AND tags->'man_made'='surveillance' 
  AND geom && ST_SetSRID('BOX3D(4 52,5 53)'::box3d,4326);

Performansla ilgili daha fazla ipucu için: http://postgis.refractions.net/docs/ch06.html


2

Sorgunuzla ilgili sorun tags->'man_made'='surveillance'yan tümcedir. Bu, Postgres'i hstore etiketlerini genişletmeye zorlar ve dizinin kullanılmasına izin vermez. Bunu @>(içerir) kullanarak yeniden yazarsanız , dizin kullanımına izin verir.

Bir dikdörtgeni sorguladığınız için &&ST_Within yerine kullanabilirsiniz . ST_Within değerlendirmek o kadar karmaşık değil ve ST_Within dolaylı olarak bir &&kontrol yapar, çünkü bu küçük bir kazanç olacaktır .

Ek bir hız artışı, etiketlerde GIST dizini yerine bir GIN dizini kullanmak olacaktır. GIN dizinlerinin oluşturulması daha uzun sürer, ancak daha hızlıdır.

Sorgunun tamamı

SELECT n.geom,n.tags,n.tstamp,u.name FROM nodes AS n INNER JOIN users AS u ON n.user_id = u.id WHERE tags @> hstore('man_made', 'surveillance') AND geom && ST_GeomFromText('POLYGON((4.0 52.0,5.0 52.0,5.0 53.0,4.0 53.0,4.0 52.0))',4326);

Belirli bir etiketi çok fazla sorgulayacağınızı biliyorsanız, üzerinde kısmi bir dizin oluşturabilirsiniz CREATE INDEX ON nodes ( tags->'man_made' ) WHERE (tags->'man_made' IS NOT NULL);.

Bu, WHERE koşulunun tags->'man_made'='surveillance'dizini kullanmasına izin verecektir . Ne yazık ki, bu dizin @>sorgulara yardımcı olamaz ve GIN veya GIST dizinleri tags->'foo'sorgulara yardımcı olamaz , bu nedenle sorguları sahip olduğunuz dizinlerle eşleştirmeniz gerekir.


tags @>hstore()Kullanmayla ilgili tavsiyeler, sorgumu büyük ölçüde geliştirdi, teşekkürler.
alphabetasoup

1

bunun yerine şunu deneyin:

N.geom, n.tags, n.tstamp, u.name SEÇİMİ düğümlerden AS n INNER JOIN kullanıcıları AS u ON olarak n.user_id = u.id NEREDE etiketleri @> 'man_made => surveillance' :: hstore AND ST_Within (geom , ST_GeomFromText ('POLYGON ((4.0 52.0,5.0 52.0,5.0 53.0,4.0 53.0,4.0 52.0))', 4326));

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.