mysql spatial索引仅支持innodb(≥5.7.5)和myisam,必须建在非空geometry类单列上;创建需满足三条件:空间类型字段、not null约束、显式spatial index语法;仅mbr类函数及8.0.16+的st_distance_sphere等特定查询能有效利用索引。

MySQL 的 Spatial 索引只支持 MyISAM 和 InnoDB(5.7.5+),且必须建在单个 GEOMETRY 列上;POINT 字段用 SPATIAL INDEX 有效,但 LINESTRING 或 POLYGON 查询性能仍可能陡降,别盲目加索引。
创建 Spatial 索引前必须满足的三个条件
MySQL 对 Spatial 索引有硬性限制,缺一不可:
-
列类型必须是GEOMETRY、POINT、LINESTRING、POLYGON等空间类型(不能是TEXT或VARCHAR存 WKT) - 表引擎必须是
InnoDB(≥5.7.5)或MyISAM(旧版兼容,但不推荐);MEMORY、CSV等引擎完全不支持 - 该列不能有
NULL值——CREATE SPATIAL INDEX会直接报错ERROR 1464 (HY000): Table storage engine for 't' doesn't support SPATIAL indexes或ERROR 1466 (HY000): The used table type doesn't support SPATIAL indexes,其实根源常是隐式NULL或引擎不匹配
正确创建 Spatial 索引的语法与常见错误
语法看着简单,但错一个字符就失败:
ALTER TABLE locations ADD COLUMN coord POINT NOT NULL SRID 4326; ALTER TABLE locations ADD SPATIAL INDEX idx_coord (coord);
注意点:
- 必须显式声明
NOT NULL,哪怕你确定没空值;SRID推荐显式指定(如4326),否则 MySQL 8.0+ 默认为0,后续用ST_Distance_Sphere()会报错ER_NOT_ST_SPATIAL - 不能在
CREATE TABLE语句里直接写SPATIAL KEY——必须先建表、再ADD SPATIAL INDEX,否则报错ERROR 1178 (42000) - 索引名不能省略(即不能写
ADD SPATIAL INDEX (coord)),MySQL 要求命名,否则报错ERROR 1064
哪些查询能真正用上 Spatial 索引?
不是所有含 ST_* 函数的查询都会走索引。真正触发索引扫描的只有:
-
MBRContains()、MBRWithin()、MBRIntersects()—— 注意是MBR*(最小边界矩形),不是ST_Contains() -
ST_Within()和ST_Distance_Sphere()在WHERE中配合ST_Distance_Sphere() 时,MySQL 8.0.16+ 才支持索引加速(需确保列有 SRID 且函数参数顺序正确) - 典型高效写法:
SELECT * FROM locations WHERE MBRContains(ST_GeomFromText('POLYGON((...))'), coord); - 低效陷阱:
WHERE ST_Distance(coord, @p) 不走索引;必须改写为 <code>WHERE ST_Distance_Sphere(coord, @p) 且 <code>@p是POINT类型 + 表中coord有SRID 4326
为什么加了 Spatial 索引查询还是慢?
常见原因不是索引没建好,而是数据或查询模式越过了 R-Tree 索引能力边界:
- 高密度点聚集(比如城市中心 10 万 POI 都落在同一 MBR 内),索引退化为全表扫描
- 用
ST_Intersection()或ST_Union()等计算密集型函数,索引只用于初筛,主耗时在几何运算本身 -
InnoDB的 Spatial 索引不支持Covering Index,SELECT *必然回表;若只需 ID 和距离,先用MBRContains拿 ID,再 JOIN 查详情 - 没做数据清洗:存在自相交
POLYGON或非法坐标(如纬度 95°),会导致ST_IsValid()返回0,部分函数静默失败或索引失效
真正关键的不是“有没有索引”,而是“查询是否落在 R-Tree 的 MBR 过滤能力范围内”——超出这个范围,加多少索引也没用。











