Rya*_*zel 216 mysql gis location
我目前在mysql数据库中的位置不到一百万个,都有经度和纬度信息.
我试图通过查询找到一个点和许多其他点之间的距离.它没有我想要的那么快,尤其是每秒100次点击.
是否有更快的查询或可能比mysql更快的系统?我正在使用此查询:
SELECT
name,
( 3959 * acos( cos( radians(42.290763) ) * cos( radians( locations.lat ) )
* cos( radians(locations.lng) - radians(-71.35368)) + sin(radians(42.290763))
* sin( radians(locations.lat)))) AS distance
FROM locations
WHERE active = 1
HAVING distance < 10
ORDER BY distance;
Run Code Online (Sandbox Code Playgroud)
注意:提供的距离以英里为单位.如果您需要公里数,请使用6371而不是3959.
Qua*_*noi 112
使用表中Point的Geometry数据类型值创建点MyISAM.从Mysql 5.7.5开始,表现在InnoDB也支持SPATIAL索引.
SPATIAL在这些点上创建索引
使用MBRContains()查找值:
SELECT *
FROM table
WHERE MBRContains(LineFromText(CONCAT(
'('
, @lon + 10 / ( 111.1 / cos(RADIANS(@lon)))
, ' '
, @lat + 10 / 111.1
, ','
, @lon - 10 / ( 111.1 / cos(RADIANS(@lat)))
, ' '
, @lat - 10 / 111.1
, ')' )
,mypoint)
Run Code Online (Sandbox Code Playgroud),或者,在MySQL 5.1上面:
SELECT *
FROM table
WHERE MBRContains
(
LineString
(
Point (
@lon + 10 / ( 111.1 / COS(RADIANS(@lat))),
@lat + 10 / 111.1
),
Point (
@lon - 10 / ( 111.1 / COS(RADIANS(@lat))),
@lat - 10 / 111.1
)
),
mypoint
)
Run Code Online (Sandbox Code Playgroud)
这将选择框内大致的所有点(@lat +/- 10 km, @lon +/- 10km).
这实际上不是一个盒子,而是一个球形矩形:球体的纬度和经度束缚段.这可能与Franz Joseph Land上的一个普通矩形不同,但在大多数有人居住的地方都非常接近.
应用其他过滤以选择圆内的所有内容(不是方形)
可能应用额外的精细过滤来考虑大圆距离(对于大距离)
Bin*_*ier 97
不是MySql特定的答案,但它会提高你的sql语句的性能.
你有效地做的是计算到表中每个点的距离,看它是否在给定点的10个单位内.
在运行这个sql之前你可以做的是创建四个点,在一侧绘制一个20个单位的框,你的点位于中心即.(x1,y1)...(x4,y4),其中(x1,y1)是(给定长+10个单位,给定为+10个单位)...(给定长 - 10个单位,给予-10个单位). 实际上,你只需要两个点,左上角和右下角称它们(X1,Y1)和(X2,Y2)
现在你的SQL语句使用这些点从你的给定点排除肯定超过10u的行,它可以使用纬度和经度上的索引,因此将比你现有的快几个数量级.
例如
select . . .
where locations.lat between X1 and X2
and locations.Long between y1 and y2;
Run Code Online (Sandbox Code Playgroud)
框方法可以返回误报(您可以从框中获取距离给定点大于10u的点),因此您仍需要计算每个点的距离.然而,这将再次快得多,因为你已经大大限制了要测试的点数.
我把这种技术称为"在盒子里面思考":)
编辑:这可以放在一个SQL语句中吗?
我不知道mySql或Php能做什么,抱歉.我不知道最好的地方是建立四个点,或者如何将它们传递给Php中的mySql查询.但是,一旦获得了这四点,就没有什么能阻止你将自己的SQL语句与我的结合起来了.
select name,
( 3959 * acos( cos( radians(42.290763) )
* cos( radians( locations.lat ) )
* cos( radians( locations.lng ) - radians(-71.35368) )
+ sin( radians(42.290763) )
* sin( radians( locations.lat ) ) ) ) AS distance
from locations
where active = 1
and locations.lat between X1 and X2
and locations.Long between y1 and y2
having distance < 10 ORDER BY distance;
Run Code Online (Sandbox Code Playgroud)
我知道使用MS SQL我可以构建一个声明四个浮点数(X1,Y1,X2,Y2)并在"主"选择语句之前计算它们的SQL语句,就像我说的,我不知道这是否可以用MySQL的.但是我仍然倾向于在C#中构建四个点并将它们作为参数传递给SQL查询.
抱歉,我无法提供更多帮助,如果有人能够回答MySQL和Php的具体部分,请随时编辑此答案.
Bra*_*rks 13
在这篇博客文章中,发布了以下MySql函数.我没有对它进行过多次测试,但是根据我从帖子中收集到的内容,如果您的纬度和经度字段已编入索引,这可能对您有用:
DELIMITER $$
DROP FUNCTION IF EXISTS `get_distance_in_miles_between_geo_locations` $$
CREATE FUNCTION get_distance_in_miles_between_geo_locations(
geo1_latitude decimal(10,6), geo1_longitude decimal(10,6),
geo2_latitude decimal(10,6), geo2_longitude decimal(10,6))
returns decimal(10,3) DETERMINISTIC
BEGIN
return ((ACOS(SIN(geo1_latitude * PI() / 180) * SIN(geo2_latitude * PI() / 180)
+ COS(geo1_latitude * PI() / 180) * COS(geo2_latitude * PI() / 180)
* COS((geo1_longitude - geo2_longitude) * PI() / 180)) * 180 / PI())
* 60 * 1.1515);
END $$
DELIMITER ;
Run Code Online (Sandbox Code Playgroud)
示例用法: 假设一个名为Places的表格包含字段纬度和经度:
从地点选择get_distance_in_miles_between_geo_locations(-34.017330,22.809500,纬度,经度)作为distance_from_input;
从这篇文章中抓住了所有人
小智 9
SELECT * FROM (SELECT *,(((acos(sin((43.6980168*pi()/180)) *
sin((latitude*pi()/180))+cos((43.6980168*pi()/180)) *
cos((latitude*pi()/180)) * cos(((7.266903899999988- longitude)*
pi()/180))))*180/pi())*60*1.1515 ) as distance
FROM wp_users WHERE 1 GROUP BY ID limit 0,10) as X
ORDER BY ID DESC
Run Code Online (Sandbox Code Playgroud)
这是MySQL中的点之间的距离计算查询,我在一个长数据库中使用它,它工作得很完美!注意:根据您的要求进行更改(数据库名称,表名称,列等).
set @latitude=53.754842;
set @longitude=-2.708077;
set @radius=20;
set @lng_min = @longitude - @radius/abs(cos(radians(@latitude))*69);
set @lng_max = @longitude + @radius/abs(cos(radians(@latitude))*69);
set @lat_min = @latitude - (@radius/69);
set @lat_max = @latitude + (@radius/69);
SELECT * FROM postcode
WHERE (longitude BETWEEN @lng_min AND @lng_max)
AND (latitude BETWEEN @lat_min and @lat_max);
Run Code Online (Sandbox Code Playgroud)
小智 7
如果你使用MySQL 5.7.*,那么你可以使用st_distance_sphere(POINT,POINT).
Select st_distance_sphere(POINT(-2.997065, 53.404146 ), POINT(58.615349, 23.56676 ))/1000 as distcance
Run Code Online (Sandbox Code Playgroud)
小智 6
select
(((acos(sin(('$latitude'*pi()/180)) * sin((`lat`*pi()/180))+cos(('$latitude'*pi()/180))
* cos((`lat`*pi()/180)) * cos((('$longitude'- `lng`)*pi()/180))))*180/pi())*60*1.1515)
AS distance
from table having distance<22;
Run Code Online (Sandbox Code Playgroud)
一个MySQL函数,它返回两个坐标之间的米数:
CREATE FUNCTION DISTANCE_BETWEEN (lat1 DOUBLE, lon1 DOUBLE, lat2 DOUBLE, lon2 DOUBLE)
RETURNS DOUBLE DETERMINISTIC
RETURN ACOS( SIN(lat1*PI()/180)*SIN(lat2*PI()/180) + COS(lat1*PI()/180)*COS(lat2*PI()/180)*COS(lon2*PI()/180-lon1*PI()/180) ) * 6371000
Run Code Online (Sandbox Code Playgroud)
要以其他格式返回值,请6371000在您选择的单位中将函数中的替换为地球半径。例如,公里为公里6371,英里为3959。
要使用该函数,只需像在MySQL中的其他任何函数一样调用它即可。例如,如果您有一个表格city,则可以找到每个城市到每个其他城市之间的距离:
SELECT
`city1`.`name`,
`city2`.`name`,
ROUND(DISTANCE_BETWEEN(`city1`.`latitude`, `city1`.`longitude`, `city2`.`latitude`, `city2`.`longitude`)) AS `distance`
FROM
`city` AS `city1`
JOIN
`city` AS `city2`
Run Code Online (Sandbox Code Playgroud)
我需要解决类似的问题(按距单个点的距离来过滤行),并通过将原始问题与答案和注释结合起来,我想出了对MySQL 5.6和5.7都适用的解决方案。
SELECT
*,
(6371 * ACOS(COS(RADIANS(56.946285)) * COS(RADIANS(Y(coordinates)))
* COS(RADIANS(X(coordinates)) - RADIANS(24.105078)) + SIN(RADIANS(56.946285))
* SIN(RADIANS(Y(coordinates))))) AS distance
FROM places
WHERE MBRContains
(
LineString
(
Point (
24.105078 + 15 / (111.320 * COS(RADIANS(56.946285))),
56.946285 + 15 / 111.133
),
Point (
24.105078 - 15 / (111.320 * COS(RADIANS(56.946285))),
56.946285 - 15 / 111.133
)
),
coordinates
)
HAVING distance < 15
ORDER By distance
Run Code Online (Sandbox Code Playgroud)
coordinates是具有类型的字段,POINT并且具有用于计算距离的SPATIAL索引
6371(以公里
56.946285为单位)是中心点的纬度是中心点
24.105078的经度
10是以公里为单位的最大距离
在我的测试中,MySQL在coordinates字段上使用SPATIAL索引来快速选择矩形内的所有行,然后计算所有已过滤位置的实际距离,以排除矩形角中的位置,而仅将圆内的位置保留。
这是我的结果的可视化:
灰色星状图显示地图上的所有点,黄色星状图是MySQL查询返回的点。矩形的角(但在圆的外部)内的灰星MBRContains()由HAVING子句选择,然后取消选择。
| 归档时间: |
|
| 查看次数: |
184171 次 |
| 最近记录: |