2016-03-21 8 views
2

Ich habe Probleme mit dem Erstellen einer Verknüpfung von Tabellen. Die Abfrage wird für immer ausgeführt. Ich habe offene Radwege in einer Tabelle mit allen Attributen.PostgreSQL - sehr langsame Tabelle Join auf OSM-Daten

Table planet_osm_line 
osm_id bigint, 
route text, 
name text, 
network text, 
osmc_color text, 
reversed text, 
state text, 
"instance:cycle" text, 
"relation:id" text, 
ref text, 
description text, 
distance text, 
tags hstore, 
way geometry(LineString,900913) 

Einige Zeilen dupliziert werden (2 oder mehr Routen auf einer Art und Weise), damit ich gefiltert einzigartige Linien in einer anderen Tabelle, und ich versuchte, sie mit Daten aus planet_osm_line zu fusionieren:

DROP TABLE IF EXISTS public.bicycle_merge; 
CREATE TABLE public.bicycle_merge AS 

WITH singleRow as ( 
    select count(way), way 
    from planet_osm_line 
    WHERE route IN ('bicycle') 
    group by way 
    having count(way) = 1 
) 
SELECT P.* 
FROM planet_osm_line P 
JOIN singleRow S 
    ON P.way = S.way 
; 

Diese Abfrage läuft für immer ... Verzeihen Sie meine neue Frage, aber was mache ich falsch?

"Nested Loop (cost=28767.43..172920474.87 rows=5892712 width=335)" 
" Join Filter: (p.way = s.way)" 
" CTE singlerow" 
" -> GroupAggregate (cost=27040.24..28767.43 rows=76764 width=218)" 
"   Filter: (count(planet_osm_line1.way) = 1)" 
"   -> Sort (cost=27040.24..27232.15 rows=76764 width=218)" 
"    Sort Key: planet_osm_line1.way" 
"    -> Seq Scan on planet_osm_line1 (cost=0.00..4543.55  rows=76764 width=218)" 

Planet_osm_line Tabelle hat etwa 70.000 Zeilen. Einzigartige Geometrien sind etwa 50.000. Diese Abfrage funktioniert mit einer kleinen Menge von Daten, aber jetzt habe ich es mit Fahrradrouten im ganzen Land (Polen) zu tun. Vielen Dank im Voraus!

+0

'Gruppe mit Weg zählen (Weg) = 1 'im Wesentlichen tut nichts, Sie könnten' verschiedene Weg von Planet_osm_line' wählen. Aber das erfordert kein CTE, das als Optimierungsbarriere dient, also könntest du einfach 'SELECT DISTINCT ON (Weg) * FROM planet_osm_line WHERE route =' Fahrrad 'ORDER BY way' verwenden. – pozs

+0

Dies funktioniert tatsächlich, aber es listet auch die Zeilen, die Duplikate haben. Ich möchte das vermeiden. Ich brauche die Zeilen, die nur in der Tabelle existieren. – Voyteck

+0

was definiert ein Duplikat? 'distinct on (way)' sollte mehrere Zeilen mit der gleichen 'way'-Spalte entfernen. Oder Sie möchten alle Zeilen löschen, die Duplikate enthalten (und nicht nur alle bis auf eine)? – pozs

Antwort

6

Sie fügen zwei ebene Geometrien hinzu. Dies bedeutet, dass Sie die Geometrien Byte für Byte binär zwischen allen möglichen Übereinstimmungen vergleichen. Das wird in der Tat sehr viel Zeit in Anspruch nehmen. In Ihrer EXPLAIN ANALYZE kostet der CTE 28.767; Die Verbindung ist ein Faktor 6000 größer.

Stattdessen sollten Sie testen, ob zwei Geometrien einander berühren (da OSM richtig geocodiert ist, können Sie davon ausgehen, dass es keine Linienkreuzungen sind):

WITH singleRow AS ( 
    SELECT count(way), way 
    FROM planet_osm_line 
    WHERE route IN ('bicycle') 
    GROUP BY way 
    HAVING count(way) = 1 
) 
SELECT P.* 
FROM planet_osm_line P 
JOIN singleRow S ON ST_Contains(P.way, S.way);

Am Set von Zeilen abrufen Sie dies wie möglich Wenden Sie dann die Funktion ST_MakeLine() an, um die kleineren Zeilen tatsächlich zu einer zusammenzufassen.

+1

Große Antwort. Ich habe tatsächlich ST_Touches zu ST_Contains geändert und es funktioniert gut. ST_Touches funktionierte nicht richtig, aber trotzdem danke :) – Voyteck

+0

Seltsam, dass ST-Touches() nicht funktionieren würde. Antwort wird aktualisiert. – Patrick

+0

Meine Abfrage dauerte 14 Sekunden. Das ist sehr akzeptabel. Danke noch einmal! – Voyteck