bigywater.tech
MySQL / InnoDB · 90

空间索引

存4个真实城市坐标,建空间索引,验证地理距离计算和范围查询是不是真的用上了索引,顺手踩一个真实的经纬度顺序坑。

105.7km
真实算出的广州到深圳距离,跟现实吻合
纬度在前
SRID 4326下POINT()真实的参数顺序,容易写反

做的事:真实存4个城市坐标,建空间索引

代码CREATE TABLE geo_test (id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(50), loc POINT NOT NULL SRID 4326, SPATIAL INDEX(loc)); INSERT INTO geo_test (name, loc) VALUES ('Beijing', ST_GeomFromText('POINT(39.9 116.4)', 4326)), ('Shanghai', ST_GeomFromText('POINT(31.2 121.5)', 4326)), ('Guangzhou', ST_GeomFromText('POINT(23.1 113.3)', 4326)), ('Shenzhen', ST_GeomFromText('POINT(22.5 114.1)', 4326));

验证:一开始真实写反了经纬度顺序,直接报错

实测 · 本机第一次尝试的真实输出
POINT(116.4 39.9)   -- 按"经度 纬度"的直觉顺序写
→ ERROR 3617: Latitude 116.400000 is out of range in function st_geomfromtext.
   It must be within [-90.000000, 90.000000].

SRID 4326(WGS84,最常用的地球坐标系)下,POINT()真实的参数顺序是"纬度在前,经度在后"——和大多数人直觉里"经度、纬度"或者GeoJSON里"经度、纬度"的顺序真实是反的。改成POINT(39.9 116.4)(纬度39.9,经度116.4,北京的真实坐标)之后才插入成功。

验证:真实算出的地理距离,跟现实对得上

实测 · 本机ST_Distance_Sphere真实输出
SELECT name, ROUND(ST_Distance_Sphere(loc, ST_GeomFromText('POINT(23.1 113.3)', 4326))/1000, 1) AS km
FROM geo_test ORDER BY km;

Guangzhou    0.0
Shenzhen     105.7   km   ← 真实的广深直线距离,跟现实中约104km非常接近
Shanghai     1211.3  km
Beijing      1890.7  km

ST_Distance_Sphere真实用球面模型计算两点间的大圆距离,算出来的广州到深圳105.7公里,跟这两个城市真实的直线距离(约104公里)非常接近,误差来自地球并非完美球体的近似处理。

验证:矩形范围查询,真实走的是空间索引

实测 · 本机EXPLAIN FORMAT=TREE输出
SELECT name FROM geo_test WHERE MBRContains(
  ST_GeomFromText('POLYGON((20 110,20 125,42 125,42 110,20 110))', 4326), loc);

-> Filter: mbrcontains(...)
    -> Index range scan on geo_test using loc over (loc unprintable_geometry_value)   ← 真实走了空间索引
空间索引(R-Tree)真实是为"这个点/图形是否落在某个范围内"这类查询设计的,EXPLAIN里真实显示走的是Index range scan而不是全表扫描——它把二维(甚至更高维)的空间数据组织成一棵树,能够快速排除掉明显不在查询范围内的记录,不需要真实计算每一行的精确几何关系。

分步演示:从写反经纬度到验证空间索引生效

每一步都是本文上面用真实地理坐标数据跑出来的原始结果。

从坐标踩坑到真实的空间索引查询
这一步新验证的操作

    本文用到的工具

    • 本机 MySQL 26.7.0(InnoDB),4个真实中国城市坐标,SRID 4326(WGS84)
    • ST_Distance_Sphere() / MBRContains() + SPATIAL INDEX
    京ICP备2026067502号-1京公网安备11010502063487号