我有一个“places”表,其中包含lat,lng和point字段。我一直在使用半正式公式来计算lat,lng的距离,但我读到使用点场更有效率?我找不到任何关于如何做到这一点的文档。这是我的查询,因为它现在可以查询所有地点并按距离排序
SELECT `places`.*, `places`.`id` AS `pid`,
((6371*acos(cos(radians(37.776708))*cos(radians(lat))*
cos(radians(lng)-radians(-122.398050))+sin(radians(37.776708))*
sin(radians(lat))))*1000) AS `distance`
FROM `places`
WHERE `page_id` IS NOT null
ORDER BY `distance` ASC
LIMIT 40 OFFSET 0
如何更改此选项以使用表格中的“point”字段而不是lat / lng
答案 0 :(得分:2)
使用MySQL地理空间扩展进行此类操作需要做一些事情。
GEOMETRY
列,且必须为NOT NULL。您当前的查询只是通过检查位置表中的所有点并按邻近顺序对它们进行排序,找到最近的点(37.77671,-122.3980)。当你使用地理空间时,你正在做一些比这更聪明的事情。您需要建立接近限制。我们称它为半径10.0法定英里。请注意,每纬度纬度有69.0法定里程。
那你怎么做这一切?
首先让自己成为一个带有几何列的表,也许是这样的:
CREATE TABLE geoplace (
id INT NOT NULL,
geo GEOMETRY NOT NULL,
PRIMARY KEY id (id),
SPATIAL KEY geo (geo)
) ENGINE=MYISAM
然后,填充类似这样的内容,将几何Point
项放入每个geo
值。
INSERT INTO geoplace
SELECT DISTINCT id,
GEOMFROMTEXT(
CONCAT('POINT(',
lat,
' ',
lng,
')') ) AS geo
FROM places
显然,您可以将GEOMETRY列放入您想要的任何表中。但是你无法在InnoDB表中创建一个有效的空间索引;该访问方法不支持空间索引。
然后,您需要这样的查询来检索您的信息。
SELECT id, X(geo), Y(geo), distance FROM (
SELECT id, geo,r,
units * DEGREES( ACOS(
COS(RADIANS(latpoint))
* COS(RADIANS(X(geo)))
* COS(RADIANS(longpoint) - RADIANS(Y(geo)))
+ SIN(RADIANS(latpoint))
* SIN(RADIANS(X(geo))))) AS distance
FROM geoplace
JOIN (
SELECT 37.776708 AS latpoint, -122.398050 AS longpoint,
10.0 AS r, 69.0 AS units
) AS p ON (1=1)
WHERE MbrContains(GeomFromText(
CONCAT('LINESTRING(',
latpoint-(r/units),' ',
longpoint-(r /(units* COS(RADIANS(latpoint)))),
',',
latpoint+(r/units) ,' ',
longpoint+(r /(units * COS(RADIANS(latpoint)))),
')')), geo)
) AS d
WHERE distance <= r
ORDER BY distance
请注意,查询的这个伟大的毛球使用您在此子句中提供的参数:
SELECT 37.776708 AS latpoint, -122.398050 AS longpoint,
10.0 AS r, 69.0 AS units
它将使用MbrContains
进行空间矩形搜索,然后使用球面余弦定律公式计算它找到的点的距离,然后正确排序。与你开始的查询相比,这个东西运行得非常快,因为它利用了空间索引。
这里有更详细的说明。
http://www.plumislandmedia.net/mysql/using-mysqls-geospatial-extension-location-finder/
有背景。
http://www.plumislandmedia.net/mysql/haversine-mysql-nearest-loc/