mysql 5.7升级到8.0后spatial索引失效,根本原因是字段缺失显式srid且允许null,导致索引降级为btree或被优化器拒绝使用;必须先update清理null值、alter modify设not null并统一srid(如4326),再drop后重建spatial索引,且st_contains等函数参数须显式指定相同srid。

MySQL 5.7 升级到 8.0 后 SPATIAL 索引不走,不是索引丢了,而是字段 SRID 缺失 + 允许 NULL 导致索引被降级为 BTREE 或直接失效——必须重置字段约束、统一 SRID、分步重建索引。
SPATIAL 索引为什么在 8.0 里变 ALL 扫描
升级后执行 EXPLAIN 显示 type=ALL、key=NULL,但 SHOW INDEX FROM table_name 又能看到索引存在,说明索引元数据还在,只是优化器拒绝使用。根本原因是 MySQL 8.0 对空间列强制校验:SRID 必须显式声明,且字段不能为 NULL;而 5.7 允许隐式 SRID(默认 0)和 NULL 值,升级后这些旧数据在 8.0 下被视为“类型不安全”,索引自动降级或跳过。
-
SHOW CREATE TABLE t查字段定义:如果显示POINT而不是POINT SRID 4326 NOT NULL,就是问题源头 -
SHOW INDEX FROM t WHERE Key_name = 'spatial_idx'看Type列:若是BTREE而非SPATIAL,说明索引已损坏 -
SELECT ST_SRID(geom) FROM t LIMIT 5:出现NULL或混杂不同 SRID(如 0/4326),就无法建有效空间索引
重建 SPATIAL 索引的三步强制操作
不能直接 ALTER TABLE ... ADD SPATIAL INDEX,必须先清理字段再分步重建。任何跳步都会报错 ER_SPATIAL_CANT_HAVE_NULL 或 ER_UNSUPPORTED_GEOMETRY_TYPE。
- 先清理 NULL 值:
UPDATE t SET geom = ST_PointFromText('POINT(0 0)', 4326) WHERE geom IS NULL - 统一 SRID 并设为 NOT NULL:
ALTER TABLE t MODIFY geom POINT NOT NULL SRID 4326(推荐用 WGS84,即 4326) - 分两步操作:
DROP INDEX spatial_idx ON t→ 再CREATE SPATIAL INDEX spatial_idx ON t(geom)
ST_Contains 查询必须带匹配 SRID
即使索引重建成功,ST_Contains(poly, point) 还是报错或不走索引?大概率是传入的几何对象没指定 SRID。MySQL 8.0 要求两个参数 SRID 严格一致,否则拒绝使用空间索引。
- 错误写法:
ST_Contains(poly, ST_PointFromText('POINT(116.3 39.9)'))(第二个参数无 SRID) - 正确写法:
ST_Contains(poly, ST_PointFromText('POINT(116.3 39.9)', 4326))(显式声明 SRID) - 验证是否生效:
EXPLAIN SELECT * FROM t WHERE ST_Contains(poly, ST_PointFromText('POINT(116.3 39.9)', 4326)),确认key列命中索引名、rows显著下降
最易被忽略的是字段定义变更必须在 DROP INDEX 之前完成——哪怕只差一个 NOT NULL,CREATE SPATIAL INDEX 就会静默失败,而 SHOW INDEX 仍显示旧索引残留,让人误以为“重建成功”。务必按顺序执行、逐条验证。











