提高 MySQL 在 POINT(lat, long) 上性能的方法
我有一个应用程序需要查询带有纬度和经度坐标的表,这些坐标使用 MYSQL 的 POINT 数据类型存储。
我有一个存储的函数,可以查找给定 GPS 位置的给定半径内附近的纬度和经度。但是,我的表将包含数十万个条目,因此性能需要最佳。
我编写了以下存储函数,但从可能的 800,000 多行中返回大约 9,000 行需要大约 4.01 秒。有没有更好的方法来查找附近的 GPS 坐标?
这是我存储的函数:
CREATE PROCEDURE `FindNearbyPoints`(
IN RADIUS FLOAT,
IN LAT FLOAT,
IN LON FLOAT
)
BEGIN
DECLARE EARTH_RADIUS FLOAT DEFAULT 3959;
DECLARE maxLat FLOAT DEFAULT (LAT + DEGREES(RADIUS/EARTH_RADIUS));
DECLARE minLat FLOAT DEFAULT (LAT - DEGREES(RADIUS/EARTH_RADIUS));
/* compensate for degrees longitude getting smaller with increasing latitude*/
DECLARE maxLon FLOAT DEFAULT (LON + DEGREES(RADIUS/EARTH_RADIUS/COS(RADIANS(LAT))));
DECLARE minLon FLOAT DEFAULT (LON - DEGREES(RADIUS/EARTH_RADIUS/COS(RADIANS(LAT))));
SELECT *, acos(sin(LAT)*sin(radians(X(Location))) + cos(LAT)*cos(radians(X(Location)))*cos(radians(Y(Location))-LON))*EARTH_RADIUS As D
FROM (
Select *
From my_table
Where X(Location)>minLat And X(Location)<maxLat
And Y(Location)>minLon And Y(Location)<maxLon
) AS FIRST_CUT
WHERE acos(sin(LAT)*sin(X(Location)) + cos(LAT)*cos(X(Location))*cos(Y(Location)-LON))*EARTH_RADIUS < RADIUS
ORDER BY D;
END
我对该函数的大部分灵感来自: http ://www.movable-type.co.uk/scripts/latlong-db.html
I have an application that needs to query a table with latitude and longitude coordinates, which are stored using MYSQL's POINT datatype.
I have a stored function that finds nearby lats and longs within a given radius of a given GPS location. However, my table will contain hundreds of thousands of entries, so performance needs to be optimal.
I have wrote the following stored function, but it takes about 4.01 seconds to return about 9,000 rows out of a possible 800,000+ rows. Is there a better way of finding nearby GPS coordinates?
Here is my stored function:
CREATE PROCEDURE `FindNearbyPoints`(
IN RADIUS FLOAT,
IN LAT FLOAT,
IN LON FLOAT
)
BEGIN
DECLARE EARTH_RADIUS FLOAT DEFAULT 3959;
DECLARE maxLat FLOAT DEFAULT (LAT + DEGREES(RADIUS/EARTH_RADIUS));
DECLARE minLat FLOAT DEFAULT (LAT - DEGREES(RADIUS/EARTH_RADIUS));
/* compensate for degrees longitude getting smaller with increasing latitude*/
DECLARE maxLon FLOAT DEFAULT (LON + DEGREES(RADIUS/EARTH_RADIUS/COS(RADIANS(LAT))));
DECLARE minLon FLOAT DEFAULT (LON - DEGREES(RADIUS/EARTH_RADIUS/COS(RADIANS(LAT))));
SELECT *, acos(sin(LAT)*sin(radians(X(Location))) + cos(LAT)*cos(radians(X(Location)))*cos(radians(Y(Location))-LON))*EARTH_RADIUS As D
FROM (
Select *
From my_table
Where X(Location)>minLat And X(Location)<maxLat
And Y(Location)>minLon And Y(Location)<maxLon
) AS FIRST_CUT
WHERE acos(sin(LAT)*sin(X(Location)) + cos(LAT)*cos(X(Location))*cos(Y(Location)-LON))*EARTH_RADIUS < RADIUS
ORDER BY D;
END
Much of my inspiration for the function came from: http://www.movable-type.co.uk/scripts/latlong-db.html
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我不确定您的数据库是如何设置的,但您可能会考虑使用空间索引,然后构建最小边界矩形来执行查询。通过边界框返回记录后,您可以快速按距离对它们进行排序,并消除半径之外的记录。我们在基因组学中使用这种索引,并且经常非常有效地查询十亿行的数据集。
mysql 文档中有关于空间索引的详细信息。
I'm not sure how your database is set up, but you might look into using SPATIAL indexing and then constructing a minimal bounding rectangle to perform the query. Once you return records via the bounding box, you can quickly order them by distance and eliminate those that are outside of your radius. We use this kind of indexing in genomics and routinely query datasets of a billion rows quite effectively.
There are details on spatial indexing in the mysql docs.