spatial索引必须显式添加,不会自动创建;mysql不会在定义point字段时自动创建空间索引,即使引擎为innodb(≥5.7.5)且类型合规,也需手动执行create table时声明spatial index或alter table add spatial index,并满足空间类型、not null、合规引擎三条件。

SPATIAL索引必须显式添加,不会自动创建
MySQL 不会在你定义 POINT 字段时自动建空间索引——哪怕表引擎是 InnoDB(≥5.7.5)且字段类型合规,也得手动加。漏掉这步,ST_Contains()、ST_DistanceSphere() 等查询基本等于全表扫描,EXPLAIN 显示 type: ALL 就是典型信号。
正确做法分两步:
- 建表时直接声明:
CREATE TABLE t (coord POINT NOT NULL SRID 4326, SPATIAL INDEX (coord)); - 已有表补加:
ALTER TABLE t ADD SPATIAL INDEX idx_coord (coord);——注意索引名不能省略,否则报ERROR 1064
常见错误:只写 INDEX (coord) 或用 ALTER TABLE ADD INDEX,那建的是 B-tree 索引,对地理坐标完全无效。
字段必须是空间类型 + NOT NULL + 合规引擎
三个条件缺一不可,任一不满足都会让 ADD SPATIAL INDEX 失败或静默失效:
-
coord类型必须是POINT、GEOMETRY等空间类型,不能是VARCHAR存 WKT 字符串 - 该列必须显式声明
NOT NULL;即使你确认没空值,不写也会报ERROR 1466或索引创建后不生效 - 表引擎只能是
InnoDB(≥5.7.5)或MyISAM;MEMORY、CSV等引擎直接不支持,报ERROR 1464
特别注意:MySQL 8.0+ 默认 POINT 的 SRID 是 0,但地理函数如 ST_DistanceSphere() 要求 SRID=4326,建表时务必写明 SRID 4326,否则后续插入或查询会返回 NULL 或报 ER_NOT_ST_SPATIAL。
哪些查询真能走 SPATIAL 索引?
不是所有含 ST_* 的 WHERE 条件都能触发索引。真正能利用 R-tree 结构加速的,只有以下几类:
-
MBRContains(poly, point)、MBRWithin(point, poly)、MBRIntersects(a, b)—— 这些基于最小边界矩形(MBR)的判断,索引效果最直接 -
ST_Within(point, poly)和ST_Contains(poly, point)在 MySQL 8.0+ 中可借助索引做 MBR 初筛,但后续仍需逐行精确计算 ST_DistanceSphere(point_a, point_b) 仅在 MySQL 8.0.16+ 支持索引加速,且要求两点都带 SRID 4326、函数参数顺序正确(不能反写)
典型陷阱:WHERE ST_Distance(coord, @p) 永远不走索引,必须换成 <code>ST_DistanceSphere();WHERE ST_Intersects(a, b) 单独用效率低,建议前置 MBRIntersects() 过滤。
TEXT/BLOB 字段会导致 ADD SPATIAL INDEX 报错
如果表里有 TEXT 或 BLOB 类型字段(比如 description TEXT),执行 ALTER TABLE ... ADD SPATIAL INDEX 会报 ERROR 1170 (42000): BLOB/TEXT column 'xxx' used in key specification... —— 这不是空间字段的问题,而是 MySQL 旧版本(
临时解法:
- 给 TEXT 字段加前缀索引:
ALTER TABLE t MODIFY description VARCHAR(1000);或ADD INDEX idx_desc (description(255)); - 升级到 MySQL 8.0.13+,已支持在含 TEXT 字段的表上直接建 SPATIAL 索引(前提是空间字段本身满足三要素)
别被报错误导去删 TEXT 字段——它和空间索引无关,只是老版本的兼容性限制。











