在mysql中的路由上(靠近)开始和结束

在mysql中的路由上(靠近)开始和结束,mysql,performance,optimization,Mysql,Performance,Optimization,我正在开发一个搜索系统,该系统可以检测起点和终点是否在路线上(接近50公里)。我在mysql数据库中有许多路由存储为点[300k行] Structure id [primary] | id_route | id_point | lat_lng_point (spatial index) 1 1 1 [GEOMETRY - 25 B] 2 1 2 [GEOMETRY -

我正在开发一个搜索系统,该系统可以检测起点和终点是否在路线上(接近50公里)。我在mysql数据库中有许多路由存储为点[300k行]

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]
...            ...        ...        ...    
问题是如何最有效地选择起点和终点(或接近50公里)的路线(路线id)

我尝试了union[在示例中](或内部联接)这一方法,但查询大约需要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 
编辑:

我根据@Djeramon建议进行了优化,现在0.06s我不知道这是我能实现的最好的结果,如果我有50万行会怎么样:)


目前,您正在对整个路由表运行两次查询。尝试运行第一个子查询以确定具有有效起点的所有路由,并仅在这些相关路由上运行第二个子查询。这将为您节省大约50%的处理时间


一种方法是使用临时表存储第一个查询的结果。但是,您需要注意创建的开销,为其创建索引可能是个好主意。有关更多详细信息,请参阅当前正在对整个路由表运行两次查询。尝试运行第一个子查询以确定具有有效起点的所有路由,并仅在这些相关路由上运行第二个子查询。这将为您节省大约50%的处理时间


一种方法是使用临时表存储第一个查询的结果。但是,您需要注意创建的开销,为其创建索引可能是个好主意。有关更多详细信息,请参阅

您是否尝试过使用exists子查询,或仅使用简单的
条件?Union将用于一个或多个条件。另一个解决方案可能是将50公里的封套存储在一个索引计算字段中(如果您可以在计算字段上创建空间索引),然后在该字段上运行查询。嗯,我不知道如何实现您的建议,以获得相同的结果。您是否尝试过使用现有子查询,或者仅使用简单的
条件?Union将用于一个或多个条件。另一个解决方案是将50公里的封套存储在索引计算字段中(如果您可以在计算字段上创建空间索引),然后对其运行查询。嗯,我不知道如何实现您的建议,以获得相同的结果。谢谢,我按照您的建议[添加到问题中],现在0.06秒,好多了。Myabe这是最好的。我只是担心如果有50万行:)谢谢我按照你的建议[添加到问题]现在0.06秒,好多了。Myabe这是最好的。我只是担心如果有5000万行:)
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;