在mysql中的路由上(靠近)开始和结束
我正在开发一个搜索系统,该系统可以检测起点和终点是否在路线上(接近50公里)。我在mysql数据库中有许多路由存储为点[300k行]在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 -
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;