当前位置:首页 > 文章列表 > 数据库 > MySQL > MySQL GIS ST_Distance_Sphere怎样计算经纬度近似距离

MySQL GIS ST_Distance_Sphere怎样计算经纬度近似距离

来源:17golang原创 2026-11-04 08:41:58 0浏览 收藏

做“附近门店”“配送范围”或“两个坐标相距多远”时,MySQL GIS 的 ST_Distance_Sphere() 可以直接给出球面上的近似距离。它返回的是米,不是公里;对经纬度点来说,最容易出错的地方也不是函数名,而是把纬度和经度写反、误读默认半径,或者把近似距离当成高精度测地线结果。

用经纬度计算近似距离的最小写法是:先用经度作为 X、纬度作为 Y 构造相同 SRID 的 Point,再调用 ST_Distance_Sphere(point_a, point_b)。返回值除以 1000 就是公里数。

官方地址:https://dev.mysql.com/doc/refman/8.4/en/

先把函数返回值和输入边界说清楚

MySQL 8.4 文档将 ST_Distance_Sphere(g1, g2 [, radius]) 定义为计算 Point 或 MultiPoint 在球面上的最小距离,结果单位为米。省略第三个参数时,SRID 0 的经纬度 Point 使用 6370986 米作为默认半径。

这里的“经纬度”对应 WKT 中的坐标顺序:X 是经度,Y 是纬度。北京附近的点应写成 POINT(116.3974 39.9093),不能写成 POINT(39.9093 116.3974)。后者仍然像一个合法的点,却表达成了完全不同的位置。

MySQL GIS 中经度作为 X、纬度作为 Y 并输入球面距离函数的静态说明图
图1:操作示意图,展示经度、纬度、Point 和米制距离之间的输入关系;这是原创静态说明图,不是运行截图或执行证据。

用两个 Point 计算米和公里

下面用两个变量表示起点和终点。示例只展示 SQL 结构,坐标值是用于说明的固定样例;在业务代码中应使用参数绑定,不要拼接用户输入。

-- X 写经度,Y 写纬度;两个点都使用 SRID 0
SET @start_point = ST_GeomFromText('POINT(116.3974 39.9093)', 0);
SET @end_point = ST_GeomFromText('POINT(121.4737 31.2304)', 0);

-- 函数返回米;除以 1000 后再四舍五入为公里
SELECT ST_Distance_Sphere(@start_point, @end_point) AS distance_meters,
       ROUND(ST_Distance_Sphere(@start_point, @end_point) / 1000, 2)
         AS distance_kilometers;

同一个距离表达式被调用两次时,阅读上比较直观,但复杂查询中可以先在子查询或应用层保存一次结果。返回值是数值距离,单位转换只改变展示单位,不会改变函数内部使用的球面模型。

从经纬度列生成点,再筛选半径内数据

如果表中分别保存了 longitude 和 latitude,可以在查询中临时构造 Point。下面用 5 公里作为示例半径,并把筛选条件保持为米制,避免把公里和米混用。

-- 门店坐标表中的 longitude 是经度,latitude 是纬度
SET @user_longitude = 116.3974;
SET @user_latitude = 39.9093;
SET @radius_meters = 5000;

-- 先计算距离,再只保留半径内的门店;NULL 坐标不会满足条件
SELECT s.id,
       s.name,
       ST_Distance_Sphere(
         ST_GeomFromText(
           CONCAT('POINT(', s.longitude, ' ', s.latitude, ')'), 0
         ),
         ST_GeomFromText(
           CONCAT('POINT(', @user_longitude, ' ', @user_latitude, ')'), 0
         )
       ) AS distance_meters
FROM store AS s
WHERE s.longitude IS NOT NULL
  AND s.latitude IS NOT NULL
  AND ST_Distance_Sphere(
        ST_GeomFromText(
          CONCAT('POINT(', s.longitude, ' ', s.latitude, ')'), 0
        ),
        ST_GeomFromText(
          CONCAT('POINT(', @user_longitude, ' ', @user_latitude, ')'), 0
        )
      ) 

这段写法重点是表达坐标顺序和单位,并不等于所有大表都应直接全表计算。生产查询通常还要结合经纬度范围预过滤、空间列设计和执行计划,先缩小候选集,再计算精确到当前模型的距离。

SRID、范围和 NULL 不要混着处理

两个几何参数应处于相同的空间参考系。若输入是 SRID 0 的 Point,MySQL 会按经度和纬度的度数解释坐标;若使用地理空间参考系,则默认半径由该 SRS 的平均半径决定。不要只给数字加一个 SRID,就把原始坐标自动变成了另一个坐标系。

经度的常见有效范围是 (-180, 180],纬度应落在地理坐标可接受范围内。输入为空时,空间便利函数通常返回 NULL;格式错误、未定义 SRS 或不同 SRID 则可能抛出 GIS 相关错误。因此,接口层应先校验数字、范围和必填性,数据库层仍需保留必要的约束或异常处理。

-- 在写入或查询前检查范围,避免把合法数字当成合法坐标
SELECT CASE
         WHEN @longitude IS NULL OR @latitude IS NULL THEN 'missing'
         WHEN @longitude  180 THEN 'longitude_out_of_range'
         WHEN @latitude  90 THEN 'latitude_out_of_range'
         ELSE 'ok'
       END AS coordinate_status;

默认半径够用时,不要误称为高精度测距

ST_Distance_Sphere() 的优势是写法直接、返回值容易用于附近查询;它描述的是球面近似距离。地图导航的道路距离、跨复杂地形的实际行驶距离,以及对误差非常敏感的测绘场景,都不能只拿这个值当最终答案。

如果业务需要自定义球面半径,可以显式传入第三个参数,单位仍是米:

-- 自定义球面半径时仍使用米;数值应来自明确的业务或模型约定
SELECT ST_Distance_Sphere(
         ST_GeomFromText('POINT(116.3974 39.9093)', 0),
         ST_GeomFromText('POINT(121.4737 31.2304)', 0),
         6371000
       ) AS distance_meters;

不要为了让结果“看起来更准”随意调整半径。先明确坐标的 SRS、结果允许的误差和下游用途,再决定使用默认半径、自定义半径,还是改用更适合的空间距离函数。

MySQL GIS 距离筛选中米制半径、候选点和近似边界的静态说明图
图2:结果示意图,展示距离值、半径筛选和球面近似边界的关系;这是原创静态说明图,不代表某次线上查询结果。

把 ST_Distance_Sphere 和 ST_Distance 区分开

问题ST_Distance_Sphere判断建议
结果单位米展示公里时再除以 1000
默认模型球面近似附近检索、粗粒度排序可优先考虑
坐标顺序经度 X、纬度 Y构造 WKT 时固定检查
精度预期不是道路或测绘结果高精度业务先核对 SRS 和函数选择
大表成本逐行计算可能昂贵先做候选范围缩小,再做距离计算

我在实际排查这类 SQL 时,通常先看三个值:坐标顺序是否正确、距离单位是否统一、输入点是否处于同一 SRID。三项都成立后,再讨论空间索引和候选集优化,效率会比一开始盯着公式更高。

为什么算出来的距离特别大?

优先检查是否把纬度写在 X、经度写在 Y。还要检查单位是否把米直接展示成公里,以及是否把原始坐标误当成已经转换过的坐标。

能不能直接传经纬度两个数字?

不能把两个数字当作函数的两个坐标参数。先用 ST_GeomFromText、ST_PointFromText 或表中的空间列构造几何对象,再传给距离函数。

为什么两个点的结果是 NULL?

先看任一输入是否为 NULL,再检查几何文本、SRID 和列值范围。返回 NULL 与参数错误不是一回事,应用层应分别记录缺失值和 GIS 异常。

归纳起来,MySQL GIS 计算经纬度近似距离的关键不是记住一条公式,而是建立稳定的输入契约:经度在前、纬度在后;同一 SRID;结果按米处理;近似距离只用于适合的业务边界。官方参考可从 https://dev.mysql.com/doc/refman/8.4/en/spatial-convenience-functions.html 开始。

版本声明
本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
MySQL JSON_TABLE怎样把缺失字段和 JSON null 区分开MySQL JSON_TABLE怎样把缺失字段和 JSON null 区分开
上一篇
MySQL JSON_TABLE怎样把缺失字段和 JSON null 区分开
MySQL roles怎样为只读账号组合最小权限
下一篇
MySQL roles怎样为只读账号组合最小权限
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • PubMedQA数据集详解:生物医学问答基准、功能与应用指南
    PubMedQA
    深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
    879次使用
  • H2O EvalGPT:开源LLM大模型评估与排行榜工具
    H2O EvalGPT
    H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
    875次使用
  • LMArena是什么?伯克利AI模型评估平台使用指南与功能解析
    LMArena
    LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
    957次使用
  • 斯坦福HELM:大语言模型Holistic Evaluation整体评估框架详解
    HELM
    深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
    939次使用
  • MMBench详解:多模态大模型基准测试、功能特点与使用指南
    MMBench
    MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
    766次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议 和 隐私政策
返回登录
  • 重置密码