我有一个拥有4万个场地的数据库,现在正在增长。从数据库中有效地选择最近的(距离)记录
假设我是红点
我希望能够尽快找回最接近的纪录。
但距离太远,下一个项目可能是任何东西。而且也可能有0-n个匹配。但是当我只是在寻找1时,是否需要加载所有40000个结果?
如何根据距离对记录进行排序?应该在MYSQL还是PHP中完成? 此计算几乎发生在每个用户每页的每个请求上,因此解决方案需要很快。
编辑感谢您的快速和有希望的答案,我需要检查这些资源,并在几天内接受/评论答案。
我有一个拥有4万个场地的数据库,现在正在增长。从数据库中有效地选择最近的(距离)记录
假设我是红点
我希望能够尽快找回最接近的纪录。
但距离太远,下一个项目可能是任何东西。而且也可能有0-n个匹配。但是当我只是在寻找1时,是否需要加载所有40000个结果?
如何根据距离对记录进行排序?应该在MYSQL还是PHP中完成? 此计算几乎发生在每个用户每页的每个请求上,因此解决方案需要很快。
编辑感谢您的快速和有希望的答案,我需要检查这些资源,并在几天内接受/评论答案。
最简单的方法是简单计算每条记录的距离并按此值排序。问题是:这是非常昂贵的,并且您不能使用该索引。您可以通过仅查看记录的子集来降低成本,也许可以通过边界框来限制,正如一些海报在此建议的那样。
如果您想要一个清晰快速的解决方案,请查看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;
请注意,有一个特殊的SPATIAL INDEX与通常的数据库索引可以利用 – Prasad 2012-05-23 16:16:12
这个问题将在本Scribd介绍(理论+数学公式+ MySQL的): Geo Distance with MySQL
我希望它涵盖了你需要
一切按照此article on Movable Type(wi)所述创建一个“边界框”以用于SQL查询中的WHERE子句中PHP代码示例),然后在查询中包含Haversine公式以计算实际距离,并按距离ASC对结果进行排序。最近的场地将成为结果集中的第一个回报。
它的边框,可以帮助你的表现,因为这意味着你只能做你的数据
的一小部分昂贵的距离计算如果初始查询不返回任何记录,拓宽边界框,然后再次执行查询,直到获得响应。
除了通过反复试验,没有找到距离的有效方法。也就是说,使用MySQL,您不能通过距离目标的距离对记录进行排名,然后选择最上面的记录。最好的办法是选择一个你认为距离最近的记录的距离。太大的数字,你会得到太多的记录,太小的数字,你不会得到任何。假设你选择40个单位。
WHERE xcoord BETWEEN n - 40 AND n + 40 AND ycoord BETWEEN n - 40 AND n + 40
现在你已经得到了所有与坐标记录的80×80盒里面,你的目标为中心(框会有点歪斜,如果你在经度和纬度工作,但那并不重要)。现在,如果您正在处理经纬度,请使用Haversine方程,或者使用Pythagoras(如果它只是笛卡尔坐标)来计算目标与每个点之间的距离。
您是否尝试过在查询中包含到场地的距离(通过使用计算列),并查看速度变慢了多少? – 2011-03-07 09:25:24
@Sams Holder我已经使用简单的pythagoran计算查询了哪些场地靠近路口,脚本执行速度比分配到路口的场地慢1-2秒。 (对于一台电脑,我觉得这是一个很长的时间) – Moak 2011-03-07 09:31:29
+1做一个很好的图! – 2011-03-07 09:36:48