Próbuję obliczyć statystyki dla danych OSM za pomocą PostgreSQL 9.3.5 i PostGIS 2.1.4. Zacząłem od małego wyciągu z bawarii, który pobrałem z Geofabrik. Schemat db jest normalnym schematem API 0.6, dane zostały zaimportowane za pomocą zrzutu do Postgres (za pomocą skryptów pgsnapshot_schema_0.6 * .sql, które są dostarczane z osmozą). Wykonano również PODCIŚNIENIE ANALIZOWE.
Jedyną niestandardową rzeczą, której używam, jest tabela wielokątów, która zawiera wieloboki dla wszystkich relacji granic administracyjnych. Geometria wielokąta nie została w żaden sposób uproszczona.
To, co teraz próbuję osiągnąć, to zliczenie wszystkich węzłów, które znajdują się w admin = 6 granicach bawarii. Oto moje zapytanie SQL:
SELECT relpoly.id, count(node)
FROM bavaria.relpolygons relpoly, bavaria.nodes node
WHERE relpoly.tags @> '"boundary"=>"administrative","admin_level"=>"6"'::hstore
AND ST_Intersects(relpoly.geom, node.geom)
GROUP BY relpoly.id;
Środowisko wykonawcze tego zapytania jest straszne, ponieważ Postgres wykonuje zagnieżdżone sprzężenie pętli i skanuje wszystkie węzły pod kątem każdej granicy admin = 6. Do Twojej wiadomości, Bawaria jest podzielona na 98 admin = 6 wielokątów, aw ekstrakcie z bawarii znajduje się około 30 milionów węzłów.
Czy można uniknąć tego nieoptymalnego wykonania zapytania i powiedzieć Postgresowi, że powinien skanować wszystkie węzły tylko raz (np. Zwiększając licznik dla odpowiedniego wielokąta w zestawie wyników lub używając wskazówek)?
Edytować:
1) w węzłach bawarii istnieje indeks przestrzenny:
CREATE INDEX idx_nodes_geom ON bavaria.nodes USING gist (geom);
2) plan zapytań wygląda następująco:
HashAggregate (cost=284908.49..284908.75 rows=26 width=103)
-> Nested Loop (cost=111.27..283900.80 rows=201537 width=103)
-> Bitmap Heap Scan on relpolygons relpoly (cost=4.48..102.29 rows=26 width=5886)
Recheck Cond: (tags @> '"boundary"=>"administrative", "admin_level"=>"6"'::hstore)
-> Bitmap Index Scan on relpolygons_geom_tags (cost=0.00..4.47 rows=26 width=0)
Index Cond: (tags @> '"boundary"=>"administrative", "admin_level"=>"6"'::hstore)
-> Bitmap Heap Scan on nodes node (cost=106.79..10905.50 rows=983 width=127)
Recheck Cond: (relpoly.geom && geom)
Filter: _st_intersects(relpoly.geom, geom)
-> Bitmap Index Scan on idx_nodes_geom (cost=0.00..106.55 rows=2950 width=0)
Index Cond: (relpoly.geom && geom)
3)
Utworzyłem następujące dwa indeksy, ale plan zapytań (i środowisko wykonawcze) nie zmieniły się
CREATE INDEX relpolygons_tags_boundary on bavaria.relpolygons( (tags->'boundary') );
CREATE INDEX relpolygons_tags_admin on bavaria.relpolygons( (tags->'admin_level') );
ANALYZE bavaria.relpolygons;
źródło
boundary
iadmin_level
) do dodatkowych kolumn w tabeli i użyj ich bezpośrednio.Odpowiedzi:
Najlepszym sposobem na indeksowanie tagów hstore jest użycie indeksów GIN lub GIST, które z dokumentów obsługują @>,?,? I? | operatorzy , to znaczy wyszukują klucze i pary klucz / wartość. Podejście do używania funkcji do wyodrębniania znaczników dla indeksu B-drzewa jest uzasadnione, ale ponieważ sprawdzane są również określone pary klucz / wartość, analizator wybrał pełny skan tabeli.
Nie mam dostępu do bavaria.relpolygons, ale w oparciu o podobne zapytanie dla OSM UK dotyczące ograniczeń prędkości i znaczników autostrad, otrzymuję to dla mojego wyjaśnienia na temat następującego zapytania:
który pokazuje bezpośredni skan indeksu (przy użyciu indeksu gist), co jest zachęcające dla tabeli z 10 milionami wierszy. Indeks został utworzony za pomocą prostego:
Chociaż nie mogę sprawdzić stanu przestrzennego, wydaje mi się, że jest mniej selektywny niż
i dlatego byłby używany tylko w przypadku warunku ponownego sprawdzenia.
Jest też świetna odpowiedź SO na różnicę między indeksami GIN i GIST . Ogólne odkrycie jest takie, że chociaż indeksy GIN są większe i wolniejsze w budowie, są znacznie szybsze w przypadku problemów z wyszukiwaniem tekstu.
Przepraszam, że odpowiadam tak późno, ale ostatnio robię podobne prace na OSM i hstore, i odkryłem, że nie tylko raz zaznaczyłem to pytanie, ale że teraz mogę na nie odpowiedzieć: D.
źródło