能,ST_Distance_Sphere默认返回以米为单位的球面距离,基于WGS84椭球近似,适用于经纬度坐标;但需确保两点SRID均为4326且经度在前、纬度在后,否则可能返回NULL或结果失真。

ST_Distance_Sphere 函数能直接返回米制距离吗?
能,ST_Distance_Sphere 默认单位就是**米**,不需要额外换算。它基于球面模型(WGS84椭球近似),比平面几何函数 ST_Distance 更适合真实地理坐标(经纬度)的距离计算。
常见误用是传入普通数值坐标(如 POINT(116.3, 39.9))却没指定 SRID,导致结果偏差大甚至报错 SRID mismatch。
- 必须显式声明 SRID:用
ST_GeomFromText('POINT(long lat)', 4326)或ST_Point(long, lat, 4326) - 两个点的 SRID 必须一致,否则函数返回
NULL(不报错但无声失败) - 经度在前、纬度在后 —— 和常见直觉相反,写反会导致距离严重失真
如何在 WHERE 条件中高效筛选 5 公里内的商户?
直接在 WHERE 中写 ST_Distance_Sphere(a.loc, b.loc) 会触发全表扫描,无法利用空间索引。正确做法是先用 <code>ST_Within + ST_Buffer 做粗筛,再用 ST_Distance_Sphere 精排或过滤。
- 给地理位置字段建空间索引:
ALTER TABLE shops ADD SPATIAL INDEX idx_location (location); - 查询时组合使用:
WHERE ST_Within(location, ST_Buffer(ST_Point(116.3, 39.9, 4326), 0.05)) AND ST_Distance_Sphere(location, ST_Point(116.3, 39.9, 4326)) -
ST_Buffer的第二个参数单位是“度”,0.05° ≈ 5.5 km(赤道附近),高纬度地区需略调大;更稳妥可用ST_DistanceSphere配合LIMIT+ 应用层分页
为什么用 ST_Distance_Sphere 却得到 0 或 NULL?
多数情况不是函数本身问题,而是输入数据不合法:
- 坐标超出范围:经度不在 [-180, 180]、纬度不在 [-90, 90] → 返回
NULL - 字段值为
NULL或空字符串 → 整个表达式为NULL - 字段类型不是
POINT或未设置 SRID → 函数静默失败(尤其从 CSV 导入后忘记SET SRID) - MySQL 版本低于 5.7.6 —— 该函数在此版本才引入,低版本只能用 Haversine 手写 SQL 或升级
调试建议:先单独查 ST_AsText(location) 和 ST_SRID(location),确认值和元数据都符合预期。
和手写 Haversine 相比,ST_Distance_Sphere 有什么实际差异?
核心区别在精度模型和维护成本:
-
ST_Distance_Sphere使用更接近 WGS84 的球面近似,误差通常 - Haversine 在 MySQL 中需手动拼
ACOS(SIN(...) * SIN(...) + COS(...) * COS(...) * COS(...)) * 6371000,易出括号/弧度转换错误 -
ST_Distance_Sphere支持空间索引配合,Haversine 表达式无法走索引,大数据量下性能断崖式下降 - 如果业务已用 PostGIS,函数行为一致;但注意 MySQL 不支持
geography类型,所有操作都在geometry上完成
真正容易被忽略的是:即使用了 ST_Distance_Sphere,若原始坐标没做去噪(比如 GPS 漂移产生的异常点)、没统一坐标系(如混用 GCJ-02 和 WGS-84),结果再准也没意义。


















