Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/60.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Mysql 如何在DB中高效存储城镇间距离_Mysql_Database Design_Architecture_Nosql_Graph Databases - Fatal编程技术网

Mysql 如何在DB中高效存储城镇间距离

Mysql 如何在DB中高效存储城镇间距离,mysql,database-design,architecture,nosql,graph-databases,Mysql,Database Design,Architecture,Nosql,Graph Databases,我需要能够显示从用户选择的特定位置到n个城市/城镇的距离。这就像点击地图,在100英里内找到所有目的地,只是它不是地图,而是网页上的链接 我需要选择一个解决方案,从一个州到一个国家再到全球,这意味着从数千个地点到十万个地点 我曾想过将CITY1_ID、CITY2_ID和距离存储在关系数据库表中,但我怀疑它是否适合web应用程序(百万行) 使用NoSQL数据库或Graph DB是否可以更有效地实现这一点?或者RDBMS在设计得当的情况下是否足以解决这个问题 补充:如果我不存储在DB中,那么我将如何

我需要能够显示从用户选择的特定位置到n个城市/城镇的距离。这就像点击地图,在100英里内找到所有目的地,只是它不是地图,而是网页上的链接

我需要选择一个解决方案,从一个州到一个国家再到全球,这意味着从数千个地点到十万个地点

我曾想过将CITY1_ID、CITY2_ID和距离存储在关系数据库表中,但我怀疑它是否适合web应用程序(百万行)

使用NoSQL数据库或Graph DB是否可以更有效地实现这一点?或者RDBMS在设计得当的情况下是否足以解决这个问题


补充:如果我不存储在DB中,那么我将如何获得这样的信息:获取圣何塞100英里范围内的所有城市?

您应该为每个城市存储
城市id、纬度、经度
一个,然后根据运行时输入计算距离。

不要存储它,用经度和纬度计算它的运行时。可扩展性极强,与节省城市之间的所有距离相反

你有一个参考点(圣何塞),在你所有的城市记录中循环,并在运行时计算它(如果有很多记录,由客户机进行计算,可能是使用javascript或其他工具,因为如果你让服务器进行计算,那么很快就会付出代价)。JavaScript可能如下所示:

var R = 6371; // Radius of the earth in km
var dLat = (lat2-lat1).toRad();  // Javascript functions in radians
var dLon = (lon2-lon1).toRad(); 
var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
        Math.cos(lat1.toRad()) * Math.cos(lat2.toRad()) * 
        Math.sin(dLon/2) * Math.sin(dLon/2); 
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); 
var d = R * c; // Distance in km
以上代码来自


注意:它是以公里为单位的,因为我是荷兰人,因此我使用公制来表示类似的东西,对于任何可以表示为图形的数据类型,它都可以很好地进行缩放

如其他人所述,您可以存储每个条目的横向/纵向坐标,并在运行时使用类似于以下内容的方法计算距离,从而提供公里/英里距离输出:

function distance($lat1, $lng1, $lat2, $lng2, $miles = true)
{
        $pi80 = M_PI / 180;
        $lat1 *= $pi80;
        $lng1 *= $pi80;
        $lat2 *= $pi80;
        $lng2 *= $pi80;

        $r = 6372.797; // mean radius of Earth in km
        $dlat = $lat2 - $lat1;
        $dlng = $lng2 - $lng1;
        $a = sin($dlat / 2) * sin($dlat / 2) + cos($lat1) * cos($lat2) * sin($dlng / 2) * sin($dlng / 2);
        $c = 2 * atan2(sqrt($a), sqrt(1 - $a));
        $km = $r * $c;

        return ($miles ? ($km * 0.621371192) : $km);
}
编辑:这不适用于半径搜索中的n个匹配。考虑到给定半径内的城镇密度,最好将距离计算移动到SQL中,因为它的速度要快得多,并且可以与x公里/英里内的距离相匹配。

我多次使用过一个简单的解决方案(但不是mysql)创建一个用户定义的函数
一些距离函数
,其中包含四个参数
latitude1
longitude1
latitude2
longitude2
,返回距离,然后根据该距离函数测试所有内容并查看每个项目,距离是否小于或等于给定值。如果你只打算有几千个地点,这是非常好和有效的

如果您需要对数百万条记录运行此查询,您可能希望查看您选择的数据库有哪些GIS(地理信息系统)扩展,因为有更好的(至少在搜索能力方面)持久数据结构可用于搜索大量位置

编辑: 要给出Microsoft如何执行此操作的示例,请参见

看起来MySQL通常支持空间扩展:


编辑二:

看起来这个问题可能也有帮助


下面是一个使用RDBMS的解决方案。留两张桌子

  • 城市{纬度,城市_id}在纬度和纬度上具有聚集指数
  • 城市化{logitude,city_id}与经度上的聚集索引

当您需要从给定的纬度和经度查找特定半径内的城市时,您可以对这两个表执行有效的范围查询,以获取特定纬度和经度范围内的城市。然后,您可以仅计算与检索到的城市之间的实际距离

不计算两个城市之间的距离,而是计算100英里的边界框,然后将4个浮点变量插入数据库-浮点比较比数据库中的距离计算快得多。不利的一面是你在角落里有一点距离

PHP函数来计算边界框

function getBoundingBox($lat_degrees,$lon_degrees,$distance_in_miles) { $radius = 3963.1; // of earth in miles // bearings $due_north = 0; $due_south = 180; $due_east = 90; $due_west = 270; // convert latitude and longitude into radians $lat_r = deg2rad($lat_degrees); $lon_r = deg2rad($lon_degrees); // find the northmost, southmost, eastmost and westmost corners $distance_in_miles away // original formula from // http://www.movable-type.co.uk/scripts/latlong.html $northmost = asin(sin($lat_r) * cos($distance_in_miles/$radius) + cos($lat_r) * sin ($distance_in_miles/$radius) * cos($due_north)); $southmost = asin(sin($lat_r) * cos($distance_in_miles/$radius) + cos($lat_r) * sin ($distance_in_miles/$radius) * cos($due_south)); $eastmost = $lon_r + atan2(sin($due_east)*sin($distance_in_miles/$radius)*cos($lat_r),cos($distance_in_miles/$radius)-sin($lat_r)*sin($lat_r)); $westmost = $lon_r + atan2(sin($due_west)*sin($distance_in_miles/$radius)*cos($lat_r),cos($distance_in_miles/$radius)-sin($lat_r)*sin($lat_r)); $northmost = rad2deg($northmost); $southmost = rad2deg($southmost); $eastmost = rad2deg($eastmost); $westmost = rad2deg($westmost); //return 2 points NW corner and SE corner return array($northmost,$westmost,$southmost,$eastmost); } 函数getBoundingBox($lat_度、$lon_度、$distance_英里) { $radius=3963.1;//以英里为单位的地球 //方位 $due_north=0; $due_south=180; $due_east=90; $due_west=270; //将纬度和经度转换为弧度 $lat_r=deg2rad($lat_度); $lon_r=deg2rad($lon_度); //查找最北、最南、最东和最西的角落$distance\u in\u英里远 //原始配方来自 // http://www.movable-type.co.uk/scripts/latlong.html $northmost=asin(sin($lat_-r)*cos($distance_in_英里/半径)+cos($lat_-r)*sin($distance_in_英里/半径)*cos($due_-north)); $southerst=asin(sin($lat_-r)*cos($distance_-in_-miles/$radius)+cos($lat_-r)*sin($distance_-in-miles/$radius)*cos($due_-south)); $eastmost=$lon\u r+atan2(sin($due\u east)*sin($distance\u in\u miles/$radius)*cos($lat\u r),cos($distance\u in\u miles/$radius)-sin($lat\u r)*sin; $westmost=$lon\u r+atan2(sin($due\u west)*sin($distance\u in\u miles/$radius)*cos($lat\u r),cos($distance\u in\u miles/$radius)-sin($lat\u r)*sin; $northmost=rad2deg($northmost); $southmost=rad2deg($southmost); $eastmost=rad2deg($eastmost); $westmost=rad2deg($westmost); //返回2点西北角和东南角 返回数组($最北,$最西,$最南,$最东); } 那么您的SQL是


从表中选择*,其中纬度=$westmost和纬度>=$southermost和经度是。。。这尽管第二个“然后计算”步骤有点棘手:D存储城市距离肯定是个坏主意(每次添加一个城市距离时,您必须执行
n
calculations/
insert
)。数据库类型(RDBMS或NoSQL)没有区别。如果我不存储在DB中,那么如何存储