我想在mysql数据库表中存储位置的纬度和经度值。考虑到未来,我希望能够在特定位置的特定半径范围内找到这些位置。话虽如此,我应该将纬度和经度值存储在哪些数据类型?请你能为我提供一个创建表脚本,如下所示:
place_id | lat | long
上表中是否有一个我缺少的专栏,它将为我提供我目前可能看不到的其他信息?
感谢您的帮助。
答案 0 :(得分:21)
您应该将点存储在数据类型为Point
的单一列中,您可以使用SPATIAL
索引进行索引(如果您的表类型为MyISAM
):
CREATE SPATIAL INDEX sx_place_location ON place (location)
SELECT *
FROM mytable
WHERE MBRContains
(
LineString
(
Point($x - $radius, $y - $radius),
Point($x + $radius, $y + $radius)
)
location
)
AND Distance(Point($x, $y), location) <= $radius
这将大大提高查询速度,例如“在给定半径范围内查找所有内容”。
请注意,最好使用普通TM
度量坐标(东向和北向)而不是极坐标(纬度和经度)。对于小半径,它们足够精确,并且计算得到了极大的简化。如果你的所有点都在一个半边形并远离两极,你可以使用一个中央子午线。
当然,您仍然可以使用极坐标,但计算MBR
和距离的公式会更复杂。
答案 1 :(得分:0)
我通过大量的主题挖掘了几个小时,无法找到一个查询,返回半径内的点,以km为单位。 ST_Distance_Sphere执行此操作,但服务器是MariaDB 5.5,不支持ST_Distance_Sphere()。
管理得到一些工作,所以这是我的解决方案,与Doctrine 2.5和Doctrine CrEOF空间库兼容:
$sqlPoint = sprintf('POINT(%f %f)', $lng, $lat);
$rsm = new ResultSetMappingBuilder($this->manager);
$rsm->addRootEntityFromClassMetadata('ApiBundle\\Entity\\Place', 'p');
$query = $this->manager->createNativeQuery(
'SELECT p.*, AsBinary(p.location) as location FROM place p ' .
'WHERE (6371 * acos( cos( radians(Y(ST_GeomFromText(?))) ) ' .
'* cos( radians( Y(p.location) ) ) * cos( radians( X(p.location) ) ' .
'- radians(X(ST_GeomFromText(?))) ) + sin( radians(Y(ST_GeomFromText(?))) ) * sin( radians( Y(p.location) ) ) )) <= ?',
$rsm
);
$query->setParameter(1, $sqlPoint, 'string');
$query->setParameter(2, $sqlPoint, 'string');
$query->setParameter(3, $sqlPoint, 'string');
$query->setParameter(4, $radius, 'float');
$result = $query->getResult();
假设lng和lat是固定点的XY,则Place是具有“位置”字段POINT类型的实体。 由于MySQL的param绑定问题,我无法直接使用DQL,这就是低级本机查询的原因。 rsm是将结果映射到实体对象所必需的。但是,可以没有它。
随意使用它。我希望它会为你节省一些时间。