提高 MySQL 在 POINT(lat, long) 上性能的方法

发布于 2024-09-28 08:09:49 字数 1443 浏览 3 评论 0原文

我有一个应用程序需要查询带有纬度和经度坐标的表,这些坐标使用 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

凑诗 2024-10-05 08:09:49

我不确定您的数据库是如何设置的,但您可能会考虑使用空间索引,然后构建最小边界矩形来执行查询。通过边界框返回记录后,您可以快速按距离对它们进行排序,并消除半径之外的记录。我们在基因组学中使用这种索引,并且经常非常有效地查询十亿行的数据集。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文