当前位置: 首页 > article >正文

SQL 实战:基于经纬度的距离计算与位置查询

在位置服务(LBS)系统中,基于地理位置查询和距离计算是核心功能之一。例如:

  • 查找附近的商铺、加油站或医院。
  • 计算两点之间的实际直线距离。
  • 筛选出指定范围内的用户或设备位置。

MySQL 提供了多种方式实现地理位置查询,包括 ST_Distance_Sphere() 和经典的 Haversine 公式。本文将介绍如何使用这两种方式在 MySQL 中进行距离计算与位置筛选。


一、经纬度距离计算原理

1. 地球模型与球面距离

在这里插入图片描述


二、方法 1:使用 ST_Distance_Sphere() 计算球面距离

函数介绍
  • ST_Distance_Sphere(point1, point2) 直接返回两点之间的球面距离,结果以米为单位。
  • POINT(lng, lat) 将经纬度转换为点对象。

案例 1:计算两点之间的直线距离

需求
计算从北京天安门到上海外滩的直线距离。

天安门坐标(39.9087, 116.3975)
外滩坐标(31.2335, 121.4920)


SQL 实现
SELECT ST_Distance_Sphere(  
    POINT(116.3975, 39.9087),  
    POINT(121.4920, 31.2335)  
) AS distance_meters;

查询结果
distance_meters
1064695.78

解释

  • 结果显示北京到上海外滩的直线距离约为 1064 公里。
  • POINT(lng, lat) 将经纬度转换为地理点,ST_Distance_Sphere 计算两点的球面距离。


案例 2:查询当前位置 5 公里范围内的商铺

需求
查询距离当前定位(广州塔 23.1056, 113.32485 公里范围内的商铺信息。


表结构 shops
shop_idnamelatlng
1星巴克23.1100113.3300
2肯德基23.0920113.3100
3麦当劳23.1500113.3700
4德克士23.0900113.2500

SQL 实现
SELECT shop_id, name,  
       ST_Distance_Sphere(POINT(lng, lat), POINT(113.3248, 23.1056)) AS distance_meters  
FROM shops  
WHERE ST_Distance_Sphere(POINT(lng, lat), POINT(113.3248, 23.1056)) <= 5000  
ORDER BY distance_meters;

查询结果
shop_idnamedistance_meters
1星巴克566.43
2肯德基1887.29

解释

  • 查询范围限定为 5000 米(5 公里)。
  • 使用 WHERE 过滤距离条件,同时按照距离升序排序,方便查看最近的商铺。


三、方法 2:Haversine 公式计算距离

在不支持 ST_Distance_Sphere 的 MySQL 版本中,可以使用 Haversine 公式 实现经纬度距离计算。


案例 3:Haversine 公式计算两点间距离

SQL 实现
SELECT  
    6371000 * 2 * ASIN(  
        SQRT(  
            POWER(SIN(RADIANS((39.9087 - 31.2335) / 2)), 2) +   
            COS(RADIANS(39.9087)) * COS(RADIANS(31.2335)) *  
            POWER(SIN(RADIANS((116.3975 - 121.4920) / 2)), 2)  
        )  
    ) AS distance_meters;

结果

distance_meters
1064695.78

解释

  • 手动实现 Haversine 公式,使用三角函数计算地球表面的两点距离。
  • 6371000 表示地球平均半径,单位为米。


四、复杂位置查询:筛选指定范围内的对象


案例 4:查询用户 10 公里范围内的餐厅

需求
用户当前位置 (30.5702, 104.0648),查询 10 公里内的餐厅。


表结构 restaurants
rest_idnamelatlng
1火锅店30.5800104.0700
2烧烤店30.5000104.0000
3自助餐厅30.6100104.1100
4小吃店30.4000103.9500

SQL 实现
SELECT rest_id, name,  
       6371000 * 2 * ASIN(  
           SQRT(  
               POWER(SIN(RADIANS((30.5702 - lat) / 2)), 2) +   
               COS(RADIANS(30.5702)) * COS(RADIANS(lat)) *  
               POWER(SIN(RADIANS((104.0648 - lng) / 2)), 2)  
           )  
       ) AS distance_meters  
FROM restaurants  
HAVING distance_meters <= 10000  
ORDER BY distance_meters;

查询结果
rest_idnamedistance_meters
1火锅店1200.43
2烧烤店7890.10


五、性能优化与注意事项

  1. 建立空间索引
    如果表中存储大量地理位置数据,可以使用 空间索引 提升查询速度:
ALTER TABLE shops ADD SPATIAL INDEX (lat, lng);
  1. 限制结果集大小
    在大数据量环境下,添加 LIMIT 和分页,提高查询效率:
ORDER BY distance_meters LIMIT 10;

六、总结

  • MySQL 提供了两种方式实现基于经纬度的距离计算:
    • ST_Distance_Sphere():直接计算,简单高效,推荐使用。
    • Haversine 公式:适用于不支持 ST_Distance_Sphere 的旧版本。
  • 通过位置查询可以实现商铺筛选、附近用户查找等功能,广泛应用于 LBS 场景。

http://www.kler.cn/a/459326.html

相关文章:

  • GDPU 数据库原理 期末复习
  • 【CSS in Depth 2 精译_099】17.5:基于页面滚动的动画时间线设置(全新)+ 17.6:最后一点建议 + 17.7:本章小结
  • 活动预告 |【Part2】Microsoft 安全在线技术公开课:安全性、合规性和身份基础知识
  • MySQL面试题(updating)
  • 集线器,交换机,路由器,mac地址和ip地址知识记录总结
  • Python 字符串定义及前缀
  • 爬虫后的数据处理与使用(处理篇)
  • 数据结构(Java)——链表
  • gala-gopher
  • 在Windows10下安装Docker WSL 2 桌面版
  • 基于python大数据的图书销售系统
  • Flutter:打包apk,详细图文介绍
  • QT-----------GUI程序设计基础
  • 基于Arduino的音乐喷泉设计(论文+源码)
  • echarts:5、树状图
  • C++类与对象(三)-- 再谈构造函数(细嗦初始化列表)、static成员
  • 多进程并发执行,多线程并发服务器
  • Redis中的数据类型
  • 数据结构与算法学习笔记----约数
  • 群落生态学研究进展▌Hmsc包对于群落生态学假说的解读、Hmsc包开展单物种和多物种分析的技术细节及Hmsc包的实际应用
  • CPO-CNN-GRU-Attention、CNN-GRU-Attention、CPO-CNN-GRU、CNN-GRU四模型多变量时序预测对比
  • 基于Golang的博客系统的设计与实现
  • 【最新】17个一站式数据集成平台案例PPT下载(Apache SeaTunnel )
  • 简易CPU设计入门:本系统中的通用寄存器(三)
  • 实景三维点云处理专业软件ArcGIS根据DSM生成地表点云集
  • IS-2T2R存储器:AWS精度下降问题的解决方案