mysql真正认的空间数据类型是point、polygon、linestring、geometry等,varchar存wkt文本不被空间索引识别且无法使用st_*函数优化;建spatial索引须同时满足:列类型为具体空间类型、引擎为innodb或myisam、列显式声明not null;创建需分两步:先add column带srid,再add spatial index并指定索引名。

POINT、POLYGON、LINESTRING、GEOMETRY 这些才是 MySQL 真正认的空间数据类型,用 VARCHAR 存 WKT 文本(比如 "POINT(116.4 39.9)")不算——它压根不会被空间索引识别,也跑不了任何 ST_* 函数的优化。
建 Spatial 索引前必须满足的三个硬性条件
缺一不可,否则直接报错,不是语法问题,是底层不支持:
-
coord列类型必须是POINT/POLYGON等空间类型,不能是TEXT或VARCHAR - 表引擎必须是
InnoDB(≥5.7.5)或MyISAM;MEMORY、CVS、ARCHIVE全都不行 -
coord列必须显式声明NOT NULL——哪怕你 INSERT 时从不插NULL,没这句就卡死在ERROR 1466或ERROR 1464
正确创建 Spatial 索引的两步法(不能合并在 CREATE TABLE 里)
MySQL 不允许在建表语句中直接写 SPATIAL INDEX,必须分两步走:
先加字段(带 NOT NULL 和 SRID):
ALTER TABLE locations ADD COLUMN coord POINT NOT NULL SRID 4326;
再单独建索引(索引名不能省):
ALTER TABLE locations ADD SPATIAL INDEX idx_coord (coord);
常见翻车点:
- 漏写
SRID 4326:MySQL 8.0+ 默认SRID 0,后续调用ST_Distance_Sphere()直接报ER_NOT_ST_SPATIAL - 写成
ADD SPATIAL INDEX (coord):缺少索引名,报ERROR 1064 - 试图在
CREATE TABLE里写SPATIAL INDEX(coord):报ERROR 1178
哪些查询能真正触发 Spatial 索引?
不是所有空间函数都走索引。真正能利用 R 树结构加速的只有:
-
MBRContains()、MBRWithin()、MBRIntersects()—— 注意是MBR*,不是ST_Contains() -
ST_Distance_Sphere()在WHERE中配合时,仅 MySQL 8.0.16+ 支持索引下推,且要求列和参数都有有效 <code>SRID
典型高效写法:
SELECT * FROM locations WHERE MBRContains(ST_GeomFromText('POLYGON((...))'), coord);
典型低效写法(完全不走索引):
SELECT * FROM locations WHERE ST_Distance(coord, @p) <p>必须改成:</p><pre class="brush:php;toolbar:false;">SELECT * FROM locations WHERE ST_Distance_Sphere(coord, @p) <h3>POINT 有效,LINESTRING/POLYGON 查询性能可能陡降</h3><p>对 <code>POINT</code> 字段建 <code>SPATIAL INDEX</code> 效果明确;但如果是 <code>POLYGON</code> 字段,用来查“某点是否在多边形内”,索引能加速 <code>MBRContains()</code> 的粗筛,但最终仍要逐个计算几何关系——尤其是多边形顶点数多、形状复杂时,CPU 开销不会因为加了索引就消失。</p><p>更隐蔽的坑:<code>POLYGON</code> 字段本身体积大,索引页分裂频繁,写入性能下降比 <code>POINT</code> 明显得多,别看文档写着“支持”,实际得测写入吞吐和查询 P95 延迟。</p>











