MySQL 大圆距离(半正矢公式)
我有一个可用的 PHP 脚本,它获取经度和纬度值,然后将它们输入到 MySQL 查询中。 我想只用MySQL。 这是我当前的 PHP 代码:
if ($distance != "Any" && $customer_zip != "") { //get the great circle distance
//get the origin zip code info
$zip_sql = "SELECT * FROM zip_code WHERE zip_code = '$customer_zip'";
$result = mysql_query($zip_sql);
$row = mysql_fetch_array($result);
$origin_lat = $row['lat'];
$origin_lon = $row['lon'];
//get the range
$lat_range = $distance/69.172;
$lon_range = abs($distance/(cos($details[0]) * 69.172));
$min_lat = number_format($origin_lat - $lat_range, "4", ".", "");
$max_lat = number_format($origin_lat + $lat_range, "4", ".", "");
$min_lon = number_format($origin_lon - $lon_range, "4", ".", "");
$max_lon = number_format($origin_lon + $lon_range, "4", ".", "");
$sql .= "lat BETWEEN '$min_lat' AND '$max_lat' AND lon BETWEEN '$min_lon' AND '$max_lon' AND ";
}
有谁知道如何完全使用 MySQL? 我浏览过一些互联网,但大多数文献都非常令人困惑。
I've got a working PHP script that gets Longitude and Latitude values and then inputs them into a MySQL query. I'd like to make it solely MySQL. Here's my current PHP Code:
if ($distance != "Any" && $customer_zip != "") { //get the great circle distance
//get the origin zip code info
$zip_sql = "SELECT * FROM zip_code WHERE zip_code = '$customer_zip'";
$result = mysql_query($zip_sql);
$row = mysql_fetch_array($result);
$origin_lat = $row['lat'];
$origin_lon = $row['lon'];
//get the range
$lat_range = $distance/69.172;
$lon_range = abs($distance/(cos($details[0]) * 69.172));
$min_lat = number_format($origin_lat - $lat_range, "4", ".", "");
$max_lat = number_format($origin_lat + $lat_range, "4", ".", "");
$min_lon = number_format($origin_lon - $lon_range, "4", ".", "");
$max_lon = number_format($origin_lon + $lon_range, "4", ".", "");
$sql .= "lat BETWEEN '$min_lat' AND '$max_lat' AND lon BETWEEN '$min_lon' AND '$max_lon' AND ";
}
Does anyone know how to make this entirely MySQL? I've browsed the Internet a bit but most of the literature on it is pretty confusing.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
如果将辅助字段添加到坐标表中,则可以缩短查询的响应时间。
像这样:
如果您使用 TokuDB,如果添加集群,您将获得更好的性能
任一谓词的索引,例如,如下所示:
您需要以度为单位的基本 lat 和 lon 以及以弧度为单位的 sin(lat)、以弧度为单位的 cos(lat)*cos(lon) 和 cos(lat) *每个点的sin(lon),以弧度表示。
然后创建一个 mysql 函数,如下所示:
这给出了距离。
不要忘记在纬度/经度上添加索引,以便边界框可以帮助搜索而不是减慢搜索速度(该索引已在上面的 CREATE TABLE 查询中添加)。
给定一个只有纬度/经度坐标的旧表,您可以设置一个脚本来更新它,如下所示:(php使用meekrodb)
然后您优化实际查询以仅在真正需要时进行距离计算,例如通过限制圆(好吧,椭圆形)从内到外。
为此,您需要预先计算查询本身的几个指标:
考虑到这些准备工作,查询将类似于以下内容 (php):
上述查询上的 EXPLAIN 可能会说它没有使用索引,除非有足够的结果来触发此类索引。 当坐标表中有足够的数据时将使用索引。
你可以加
力指数 (lat_lon_idx)
到 SELECT 使其使用索引而不考虑表大小,因此您可以使用 EXPLAIN 验证它是否正常工作。
通过上述代码示例,您应该可以以最小的错误实现按距离进行对象搜索的有效且可扩展的实现。
If you add helper fields to the coordinates table, you can improve response time of the query.
Like this:
If you're using TokuDB, you'll get even better performance if you add clustering
indexes on either of the predicates, for example, like this:
You'll need the basic lat and lon in degrees as well as sin(lat) in radians, cos(lat)*cos(lon) in radians and cos(lat)*sin(lon) in radians for each point.
Then you create a mysql function, smth like this:
This gives you the distance.
Don't forget to add an index on lat/lon so the bounding boxing can help the search instead of slowing it down (the index is already added in the CREATE TABLE query above).
Given an old table with only lat/lon coordinates, you can set up a script to update it like this: (php using meekrodb)
Then you optimize the actual query to only do the distance calculation when really needed, for example by bounding the circle (well, oval) from inside and outside.
For that, you'll need to precalculate several metrics for the query itself:
Given those preparations, the query goes something like this (php):
EXPLAIN on the above query might say that it's not using index unless there's enough results to trigger such. The index will be used when there's enough data in the coordinates table.
You can add
FORCE INDEX (lat_lon_idx)
to the SELECT to make it use the index with no regards to the table size, so you can verify with EXPLAIN that it is working correctly.
With the above code samples you should have a working and scalable implementation of object search by distance with minimal error.
我必须详细地解决这个问题,所以我将分享我的结果。 这使用了
zip
表以及latitude
和longitude
表。 它不依赖于谷歌地图; 相反,您可以将其适应任何包含纬度/经度的表。查看该查询中间的这一行:
这将搜索
zip
表中距离纬度/经度点 42.81/-70.81 50.0 英里范围内最近的 30 个条目。 当您将其构建到应用程序中时,您可以在其中放置自己的点和搜索半径。如果您想以公里而不是英里为单位,请将
69
更改为111.045
,并将3963.17
更改为6378.10
询问。这里有详细的写法。 我希望它对某人有帮助。 http://www.plumislandmedia.net/mysql/haversine-mysql-nearest-loc/
I have had to work this out in some detail, so I'll share my result. This uses a
zip
table withlatitude
andlongitude
tables. It doesn't depend on Google Maps; rather you can adapt it to any table containing lat/long.Look at this line in the middle of that query:
This searches for the 30 nearest entries in the
zip
table within 50.0 miles of the lat/long point 42.81/-70.81 . When you build this into an app, that's where you put your own point and search radius.If you want to work in kilometers rather than miles, change
69
to111.045
and change3963.17
to6378.10
in the query.Here's a detailed writeup. I hope it helps somebody. http://www.plumislandmedia.net/mysql/haversine-mysql-nearest-loc/
距离25公里
for distance of 25 km
我写了一个可以计算相同的程序,
但您必须在相应的表中输入纬度和经度。
I have written a procedure that can calculate the same,
but you have to enter the latitude and longitude in the respective table.
我无法对上述答案发表评论,但请小心@Pavel Chuchuva 的答案。 如果两个坐标相同,该公式将不会返回结果。 在这种情况下,距离为空,因此该行不会按原样使用该公式返回。
我不是 MySQL 专家,但这似乎对我有用:
I can't comment on the above answer, but be careful with @Pavel Chuchuva's answer. That formula will not return a result if both coordinates are the same. In that case, distance is null, and so that row won't be returned with that formula as is.
I'm not a MySQL expert, but this seems to be working for me:
我认为我的 javascript 实现可以很好地参考:
I thought my javascript implementation would be a good reference to:
在Mysql中计算距离,
从而计算出距离值,任何人都可以根据需要申请。
calculate distance in Mysql
thus distance value will be calculated and anyone can apply as required.
来自 Google 代码常见问题解答 - 创建商店定位器使用 PHP、MySQL 和 谷歌地图:
From Google Code FAQ - Creating a Store Locator with PHP, MySQL & Google Maps:
$greatCircleDistance = acos( cos($latitude0) * cos($latitude1) * cos($longitude0 - $longitude1) + sin($latitude0) * sin($latitude1));
包含纬度和经度以弧度表示。
也是如此
您的 SQL 查询
,要获取以公里或英里为单位的结果,请将结果乘以地球的平均半径(
3959
英里、6371
公里或3440
代码>海里)您在示例中计算的是一个边界框。
如果您将坐标数据放入支持空间的 MySQL 列,您可以使用MySQL的内置功能 查询数据。
$greatCircleDistance = acos( cos($latitude0) * cos($latitude1) * cos($longitude0 - $longitude1) + sin($latitude0) * sin($latitude1));
with latitude and longitude in radian.
so
is your SQL query
to get your results in Km or miles, multiply the result with the mean radius of Earth (
3959
miles,6371
Km or3440
nautical miles)The thing you are calculating in your example is a bounding box.
If you put your coordinate data in a spatial enabled MySQL column, you can use MySQL's build in functionality to query the data.