2016-07-12 4 views
1

Я работаю над поисковой системой, которая должна определить, включена ли начальная и конечная точка (около 50 км) маршрута. У меня много маршрутов, хранящихся в DB mysql, в виде точек [300k строк].Начало и конец маршрута в 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] 
...   ...  ...  ...  

Вопрос в том, как наиболее effectivelly выбрать только маршруты (route_id), на котором (или около 50 км) начальную и конечную точки является?

Я попытался объединить [в примере] (или внутреннее соединение), который работает, но запрос занимает около 0.4s, что слишком много. Любая идея, как оптимизировать?

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:

я сделал оптимизации на основе @Djeramon советы ANO Теперь 0.06s Я не знаю, что это лучшее, что я могу достичь, и что делать, если у меня будет 50M строки:)

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

Вы пытались использовать подзапрос существует или просто с условием «и»? Союз будет использоваться для или условия. Другим решением может быть сохранение 50-километрового конверта в индексированном вычисленном поле (если вы можете создать пространственный индекс в вычисленном поле) и запустить запрос по этому вопросу. – Shadow

+0

Хм, у меня нет идеи, как реализовать свои рекомендации, чтобы получить тот же результат. – rossinelo

ответ

0

В настоящее время вы выполняете запрос дважды по всей таблице маршрутов. Попробуйте запустить первый подзапрос, чтобы определить все маршруты с допустимой начальной точкой и запустить второй подзапрос только на соответствующих маршрутах. Это должно обеспечить вам примерно 50% времени обработки.

Одним из подходов будет использование временной таблицы для хранения результата первого запроса. Однако вам нужно следить за созданными накладными расходами, и, вероятно, это хорошая идея создать для него индекс. За более подробной информацией обращайтесь к http://blog.endpoint.com/2015/02/temporary-tables-in-sql-query.html

+0

спасибо Я следил за вашим предложением [добавлено в вопрос] и теперь 0.06s, так лучше. Миабе это самое лучшее. Я просто волнуюсь, если 50M строк :) – rossinelo

Смежные вопросы