MySQL GIS ST_Distance_Sphere怎样计算经纬度近似距离
做“附近门店”“配送范围”或“两个坐标相距多远”时,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)。后者仍然像一个合法的点,却表达成了完全不同的位置。

用两个 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、结果允许的误差和下游用途,再决定使用默认半径、自定义半径,还是改用更适合的空间距离函数。

把 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 开始。
MySQL JSON_TABLE怎样把缺失字段和 JSON null 区分开
- 上一篇
- MySQL JSON_TABLE怎样把缺失字段和 JSON null 区分开
- 下一篇
- MySQL roles怎样为只读账号组合最小权限
-
- 数据库 · MySQL | 1小时前 | MySQL · mysql Performance Schema SET RESOURCE GROUP
- MySQL SET RESOURCE GROUP怎样把指定线程切换到目标资源组
- 291浏览 收藏
-
- 数据库 · MySQL | 1小时前 |
- MySQL clone plugin怎样复制实例用于测试环境
- 260浏览 收藏
-
- 数据库 · MySQL | 1小时前 | MySQL · 权限管理 ·
- MySQL roles怎样为只读账号组合最小权限
- 368浏览 收藏
-
- 数据库 · MySQL | 1小时前 | mysql JSON_TABLE JSON查询 ON EMPTY ON ERROR JSON null EXISTS PATH
- MySQL JSON_TABLE怎样把缺失字段和 JSON null 区分开
- 102浏览 收藏
-
- 数据库 · MySQL | 4小时前 |
- MySQL recursive CTE怎样限制递归查询深度
- 137浏览 收藏
-
- 数据库 · MySQL | 4小时前 |
- MySQL window function怎样在分组内取第二条记录
- 488浏览 收藏
-
- 数据库 · MySQL | 5小时前 |
- MySQL optimizer_trace怎样读取一次查询的优化决策
- 152浏览 收藏
-
- 数据库 · MySQL | 5小时前 | 数据库运维 · mysql binlog 时间范围 mysqlbinlog 增量日志
- MySQL mysqlbinlog怎样按时间范围导出增量日志
- 498浏览 收藏
-
- 数据库 · MySQL | 5小时前 | 执行计划 · 查询优化 · 数据库排查 · mysql 直方图 ANALYZE TABLE COLUMN_STATISTICS sampling-rate
- MySQL 直方图怎样检查采样比例是否过低
- 309浏览 收藏
-
- 数据库 · MySQL | 5小时前 |
- MySQL 直方图怎样判断统计信息是否需要重新采集
- 493浏览 收藏
-
- 数据库 · MySQL | 1天前 |
- MySQL 锁等待超时怎样定位阻塞事务
- 325浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 485次学习
-
- PubMedQA
- 深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
- 879次使用
-
- H2O EvalGPT
- H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
- 875次使用
-
- LMArena
- LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
- 957次使用
-
- HELM
- 深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
- 939次使用
-
- MMBench
- MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
- 766次使用
-
- MySQL 明明加了索引,为什么查询还是很慢?先查这 6 个点
- 2026-06-27 374浏览
-
- golang MySQL实现对数据库表存储获取操作示例
- 2022-12-22 499浏览
-
- golang 基于 mysql 简单实现分布式读写锁
- 2023-01-07 384浏览
-
- 详解如何利用GORM实现MySQL事务
- 2023-01-07 184浏览
-
- Go语言实现操作MySQL的基础知识总结
- 2023-01-23 265浏览

