2011-03-07 111 views
8

我有一个拥有4万个场地的数据库,现在正在增长。从数据库中有效地选择最近的(距离)记录

假设我是红点

Easy
我希望能够尽快找回最接近的纪录。

但距离太远,下一个项目可能是任何东西。而且也可能有0-n个匹配。但是当我只是在寻找1时,是否需要加载所有40000个结果? Less obvious

如何根据距离对记录进行排序?应该在MYSQL还是PHP中完成? 此计算几乎发生在每个用户每页的每个请求上,因此解决方案需要很快。

编辑感谢您的快速和有希望的答案,我需要检查这些资源,并在几天内接受/评论答案。

+0

您是否尝试过在查询中包含到场地的距离(通过使用计算列),并查看速度变慢了多少? – 2011-03-07 09:25:24

+0

@Sams Holder我已经使用简单的pythagoran计算查询了哪些场地靠近路口,脚本执行速度比分配到路口的场地慢1-2秒。 (对于一台电脑,我觉得这是一个很长的时间) – Moak 2011-03-07 09:31:29

+2

+1做一个很好的图! – 2011-03-07 09:36:48

回答

3

最简单的方法是简单计算每条记录的距离并按此值排序。问题是:这是非常昂贵的,并且您不能使用该索引。您可以通过仅查看记录的子集来降低成本,也许可以通过边界框来限制,正如一些海报在此建议的那样。

如果您想要一个清晰快速的解决方案,请查看MySQL的Spatial Extensions。这些完全是为了你想要做的。这些支持:

  • 一个新的塔型“点”
  • 一种特殊的索引类型距离的查询
  • 的距离运营商进行了优化。

This HOWTO提供了一些例子:

CREATE TABLE address (
    address CHAR(80) NOT NULL, 
    address_loc POINT NOT NULL, 
    PRIMARY KEY(address), 
    SPATIAL KEY(address_loc) 
); 
CREATE TABLE cab (
    cab_id INT AUTO_INCREMENT NOT NULL, 
    cab_driver CHAR(80) NOT NULL, 
    cab_loc POINT NOT NULL, 
    PRIMARY KEY(cab_id), 
    SPATIAL KEY(cab_loc) 
); 

SELECT 
    c.cab_driver, 
    ROUND(GLength(LineStringFromWKB(LineString(AsBinary(c.cab_loc), 
              AsBinary(a.address_loc))))) 
    AS distance 
FROM cab c, address a 
WHERE a.address = 'Foobar street 110' 
ORDER BY distance ASC LIMIT 1; 
+0

请注意,有一个特殊的SPATIAL INDEX与通常的数据库索引可以利用 – Prasad 2012-05-23 16:16:12

1

按照此article on Movable Type(wi)所述创建一个“边界框”以用于SQL查询中的WHERE子句中PHP代码示例),然后在查询中包含Haversine公式以计算实际距离,并按距离ASC对结果进行排序。最近的场地将成为结果集中的第一个回报。

它的边框,可以帮助你的表现,因为这意味着你只能做你的数据

的一小部分昂贵的距离计算如果初始查询不返回任何记录,拓宽边界框,然后再次执行查询,直到获得响应。

1

除了通过反复试验,没有找到距离的有效方法。也就是说,使用MySQL,您不能通过距离目标的距离对记录进行排名,然后选择最上面的记录。最好的办法是选择一个你认为距离最近的记录的距离。太大的数字,你会得到太多的记录,太小的数字,你不会得到任何。假设你选择40个单位。

WHERE xcoord BETWEEN n - 40 AND n + 40 AND ycoord BETWEEN n - 40 AND n + 40 

现在你已经得到了所有与坐标记录的80×80盒里面,你的目标为中心(框会有点歪斜,如果你在经度和纬度工作,但那并不重要)。现在,如果您正在处理经纬度,请使用Haversine方程,或者使用Pythagoras(如果它只是笛卡尔坐标)来计算目标与每个点之间的距离。

相关问题