2016-07-12 12 views
1

Ich arbeite an einem Suchsystem, das erkennen sollte, ob Start- und Endpunkt auf (in der Nähe von 50 km) der Route ist. Ich habe viele Routen in Mysql DB als Punkte [300k Zeilen] gespeichert.Start und Ende auf (in der Nähe) der Route in Mysql

Structure 
id [primary] | id_route | id_point | lat_lng_point (spatial index) 
1    1   1   [GEOMETRY - 25 B] 
2    1   2   [GEOMETRY - 25 B] 
3    1   3   [GEOMETRY - 25 B] 
4    1   4   [GEOMETRY - 25 B] 
5    2   1   [GEOMETRY - 25 B] 
6    2   2   [GEOMETRY - 25 B] 
...   ...  ...  ...  

Frage ist, wie die meisten effectivelly nur Routen wählen (route_id), auf dem (oder in der Nähe von 50 km) der Start- und Endpunkte sind?

Ich habe Union versucht [in Beispiel] (oder inneren Join), die funktioniert, aber die Abfrage dauert um 0.4s, die zu viel ist. Irgendeine Idee, wie man optimiert?

SELECT * FROM 
     (
      (
       SELECT DISTINCT(id_route) 
       FROM route_path2 
       WHERE ST_Contains(ST_MakeEnvelope(
            Point(($lng_start+(50/111)), ($lat_start+(50/111))), 
            Point(($lng_start-(50/111)), ($lat_start-(50/111))) 
           ), route_path2.lat_lng_point) 
      ) 
     UNION ALL 
      (
       SELECT DISTINCT(id_route) 
       FROM route_path2 
       WHERE ST_Contains(ST_MakeEnvelope(
            Point(($lng_end+(50/111)), ($lat_end+(50/111))), 
            Point(($lng_end-(50/111)), ($lat_end-(50/111))) 
           ), route_path2.lat_lng_point) 
      ) 

     ) AS t GROUP BY id_route HAVING count(*) >= 2 

EDIT:

Ich habe Optimierung basierend auf @Djeramon Beratung ano jetzt 0.06s Ich weiß nicht, das ist das beste, was ich erreichen kann, und was ist, wenn ich 50M Reihen haben:)

CREATE TEMPORARY TABLE starts_on_route AS 
SELECT DISTINCT id_route 
FROM route_path2 
WHERE ST_Contains(ST_MakeEnvelope(
        Point((17.1077+(50/111)), (48.1486+(50/111))), 
        Point((17.1077-(50/111)), (48.1486-(50/111))) 
       ), route_path2.lat_lng_point); 

CREATE INDEX starts_on_route_inx ON starts_on_route(id_route); 

SELECT DISTINCT route_path2.id_route 
FROM route_path2 
LEFT JOIN starts_on_route 
ON route_path2.id_route = starts_on_route.id_route 
WHERE ST_Contains(ST_MakeEnvelope(
    Point((18.7408+(50/111)), (49.2194+(50/111))), 
    Point((18.7408-(50/111)), (49.2194-(50/111))) 
), lat_lng_point) 
AND route_path2.id_route = starts_on_route.id_route; 
+0

Haben Sie versucht mit einer Existenz Unterabfrage oder nur mit einem einfachen 'und' Bedingung? Union würde für eine oder Bedingung verwendet werden. Eine andere Lösung könnte darin bestehen, den 50 km-Umschlag in einem indizierten berechneten Feld zu speichern (wenn Sie einen räumlichen Index für ein berechnetes Feld erstellen können) und die Abfrage darauf auszuführen. – Shadow

+0

Hmm, ich habe keine Idee, wie Sie Ihre Empfehlungen umsetzen, um das gleiche Ergebnis zu erhalten. – rossinelo

Antwort

0

Derzeit führen Sie die Abfrage zweimal für die gesamte Routentabelle aus. Versuchen Sie, die erste Unterabfrage auszuführen, um alle Routen mit einem gültigen Startpunkt zu ermitteln, und führen Sie die zweite Unterabfrage nur für diese relevanten Routen aus. Dies sollte ungefähr 50% der Verarbeitungszeit sicherstellen.

Ein Ansatz wäre die Verwendung einer temporären Tabelle zum Speichern des Ergebnisses der ersten Abfrage. Sie müssen jedoch auf den erzeugten Overhead achten, und es ist wahrscheinlich eine gute Idee, einen Index dafür zu erstellen. Für ein paar weitere Details siehe http://blog.endpoint.com/2015/02/temporary-tables-in-sql-query.html

+0

danke ich folgte Ihrem Vorschlag [Frage hinzugefügt] und jetzt 0,06s, so viel besser. Myabe ist das Beste. Ich mache mir nur Sorgen, wenn 50M Reihen :) – rossinelo