st_distance不能正确计算经纬度距离,它返回的是无物理意义的平面欧氏距离(单位“度”);st_distance_sphere才是唯一推荐的球面距离函数,返回单位为米的真实距离。

ST_Distance 在 MySQL 中根本不能正确计算经纬度距离——它返回的是平面欧氏距离(单位是“度”),不是米,也不是公里,直接用于地理距离判断会出大问题。
ST_Distance 返回的是角度差,不是真实距离
ST_Distance 函数把经纬度当成普通笛卡尔坐标处理,把 POINT(116.4, 39.9) 和 POINT(116.5, 39.9) 的差值算成 0.1,单位是“度”。但 1 度经度在赤道约 111 km,在北京约 85 km,在哈尔滨只剩约 60 km。纬度方向也非线性。所以:
- 结果无物理意义,无法跨纬度比较
- 不支持空间索引加速(即使加了
SPATIAL INDEX,WHERE 中用ST_Distance过滤仍全表扫描) - MySQL 5.6+ 虽支持该函数,但仅适合平面几何场景(如 CAD 图形、矩形区域重叠判断),不适合地理坐标
ST_Distance_Sphere 是唯一推荐的球面距离函数
MySQL 5.7.6+ 开始提供 ST_Distance_Sphere,它基于球面模型(WGS84 近似),输入两个 POINT(longitude, latitude),直接返回单位为米的球面距离:
- 必须确保参数顺序:先经度(lng),后纬度(lat)——
POINT(121.47, 31.23)✅,POINT(31.23, 121.47)❌(错序会导致结果偏差上千公里) - 字段类型必须是
POINT,且 SRID = 4326;若存的是lng和lat两个DOUBLE字段,得用ST_PointFromText(CONCAT('POINT(', lng, ' ', lat, ')'))或提前建生成列 - 返回值是浮点数(单位:米),要公里就得显式除以 1000:
ST_Distance_Sphere(p1, p2) / 1000 - 函数本身不走索引,WHERE 中直接写
ST_Distance_Sphere(...) 会强制全表扫描
WHERE 中过滤必须配合 MBRContains + 空间索引
想查“5 公里内所有门店”,不能只靠 ST_Distance_Sphere 做 WHERE 条件。正确做法是两步粗筛+精算:
- 先用
MBRContains(ST_Buffer(ST_PointFromText('POINT(121.47 31.23)'), 0.05), point_col)快速圈出大致范围(0.05 度 ≈ 5–6 km,视纬度而定) -
point_col字段必须已建空间索引:ALTER TABLE locations ADD SPATIAL INDEX idx_point (point_col); - 再在外层 SELECT 中用
ST_Distance_Sphere精确计算并排序:ORDER BY ST_Distance_Sphere(point_col, @target) LIMIT 20 - MySQL 5.7 不支持 CTE,务必用派生表包装 ORDER BY + LIMIT,否则优化器可能跳过排序
低版本 MySQL(
如果卡在 MySQL 5.6 或更老版本,ST_Distance_Sphere 会报错 FUNCTION db.ST_Distance_Sphere does not exist,也不能用 ST_Distance 替代。稳妥方案是手写 Haversine 公式:
SELECT id, name,
6371000 * ACOS(
LEAST(GREATEST(
COS(RADIANS(31.23)) * COS(RADIANS(lat)) * COS(RADIANS(lng) - RADIANS(121.47)) +
SIN(RADIANS(31.23)) * SIN(RADIANS(lat)),
-1), 1)
) AS distance_m
FROM locations
WHERE lng BETWEEN 121.42 AND 121.52
AND lat BETWEEN 31.18 AND 31.28;
注意:WHERE 中加 lng/lat 范围条件是模拟粗筛,虽不如空间索引高效,但比没过滤强得多;ACOS 参数必须用 LEAST(GREATEST(..., -1), 1) 防止浮点误差越界报错。
最常被忽略的其实是单位——ST_Distance_Sphere 返回米,不是公里;最致命的错误是经纬度顺序写反;而最容易被低估的是索引缺失导致的性能断崖——哪怕只有 10 万行,没 MBRContains + 空间索引,一次附近搜索就可能拖慢整个查询。











