空间类型概览
MYSQL 主要的类型两类。
一类是代表单个值的GEOMETRY、POINT、LINESTRING、POLYGON。其中GEOMETRY可以是任意(POINT, LINESTRING, and POLYGON)类型;
另一类是集合类型,MULTIPOINT、MULTILINESTRING、MULTIPOLYGON、GEOMETRYCOLLECTION。集合类型中的元素必须同一参考系的。
MySQL的空间类型时建立在OpenGIS Geometry Model之上,其中Geometry 是顶级类,它具有所有类型都拥有的属性。
类型属性
下面列举一些比较重要的所有类型都具有的属性:
- SRID( spatial reference identifier),指明空间参考系,可以通过INFORMATION_SCHEMA.ST_SPATIAL_REFERENCE_SYSTEMS查看具体哪些参考系。默认值是0,指的是无限平坦的笛卡尔平面
- coordinates 坐标,同SRID有关。不同参考系的同样的坐标值,不相同
- dimension:可以有−1, 0, 1, or 2这几个选择:
- -1:空的几何体
- 0:没有长度和面积的几何体
- 1:长度不为零且面积为零的几何体
- 2:面积不为零的几何体
具体类型
POINT
select ST_GeomFromText('POINT(0 0)')
拥有X和Y坐标值,可以分别通过ST_X和ST_Y查看:
SELECT ST_X(Point(12.1,23))
-- 12.1
select ST_Y(Point(12,23.12));
-- 23.12
LineString
线段,可以是曲线,能用来表示河流或者街道等。坐标,由每一对连续的点定义。
select ST_GeomFromText('LINESTRING(0 0, 10 10, 20 25, 50 60)')
Polygon
他由一组封闭的LineString对象构成起边界,可以用来表示森林或区域等;
Polygon 可以有孔,但是两个封闭的边界不是相连的;
select ST_GeomFromText('POLYGON((0 0,10 0,10 10,0 10,0 0),(5 5,7 5,7 7,5 7, 5 5))');
MultiPoint
由多个不相连且无顺序的点组成,可以用来表示一连串的小岛屿或连锁店的各个门点。
MultiLineString
一组LineString的集合,可以代表一个河流系统或一个公路系统
MultiPolygon
由一组Polygon元素(任意两个Polygon是不相交的)组成的,可以代表一个湖泊系统;
数据表示
主要有两种表示方式Well-Known Text (WKT) format和Well-Known Binary (WKB) format
Well-Known Text (WKT) format
可以使用ST_GeomFromText 将文本转成空间几何类型:
SELECT ST_GeomFromText('POINT(15 20)');
select ST_GeomFromText('LINESTRING(0 0, 10 10, 20 25, 50 60)');
select ST_GeomFromText('POLYGON((0 0,10 0,10 10,0 10,0 0),(5 5,7 5,7 7,5 7, 5 5))');
select ST_GeomFromText('MULTIPOINT ((1 1), (2 2), (3 3))');
select ST_GeomFromText('GEOMETRYCOLLECTION(POINT(10 10), POINT(30 30), LINESTRING(15 15, 20 20))');
也可以使用ST_AsText 转成文本:
select ST_AsText(ST_GeomFromText('LINESTRING(0 0, 10 10, 20 25, 50 60)'))
-- LINESTRING(0 0,10 10,20 25,50 60)
Well-Known Binary (WKB) Format
以BLOB值表示的二进制,可以通过ST_AsBinary转二进制
select ST_AsBinary(ST_GeomFromText('POINT(15 20)'));
select ST_AsBinary(ST_GeomFromText('LINESTRING(0 0, 10 10, 20 25, 50 60)'));
MySQL内部字节使用:
- 4 bytes for integer SRID (0)
- 1 byte for integer byte order (1 = little-endian)
- 4 bytes for integer type information (1 = Point)
- 8 bytes for double-precision X coordinate (1)
- 8 bytes for double-precision Y coordinate (−1)
所以一个Point占25字节。
赋值与查询
除了上面提到的可以通用的ST_GeomFromText,还有一些具体转化函数ST_LineStringFromText、ST_PointFromText、ST_PolygonFromText、ST_GeomCollFromText等
SET @g = 'POINT(1 1)';
select ST_PointFromText(@g)
SET @g ='GEOMETRYCOLLECTION(POINT(1 1),LINESTRING(0 0,1 1,2 2,3 3,4 4))';
INSERT INTO geom VALUES (ST_GeomCollFromText(@g));
查询主要通过ST_AsText和 ST_AsBinary,分别以字符串和BLOB形式获取数据;
SELECT ST_AsText(g) FROM geom;
SELECT ST_AsBinary(g) FROM geom;
索引
索引的关键字是SPATIAL INDEX,他不是B-tree结构,而是R-tree。
CREATE TABLE geom (g GEOMETRY NOT NULL SRID 4326, SPATIAL INDEX(g));
ALTER TABLE geom ADD SPATIAL INDEX(g);
CREATE SPATIAL INDEX g ON geom (g);
索引的使用主要通过 MBRContains() 和 MBRWithin()函数:
mysql> SET @poly =
-> 'Polygon((30000 15000,
31000 15000,
31000 16000,
30000 16000,
30000 15000))';
mysql> EXPLAIN SELECT fid,ST_AsText(g) FROM geom WHERE
-> MBRContains(ST_GeomFromText(@poly),g)\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: geom
type: range
possible_keys: g
key: g
key_len: 32
ref: NULL
rows: 50
Extra: Using where
1 row in set (0.00 sec)
mysql> SET @poly =
-> 'Polygon((30000 15000,
31000 15000,
31000 16000,
30000 16000,
30000 15000))';
mysql> EXPLAIN SELECT fid,ST_AsText(g) FROM g IGNORE INDEX (g) WHERE
-> MBRContains(ST_GeomFromText(@poly),g)\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: geom
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 32376
Extra: Using where
1 row in set (0.00 sec)
注意
如果几何体在语法上不符合要求,空间函数会出现问题。可以用ST_IsValid来校验:
SET @ls1 = ST_GeomFromText('LINESTRING(0 0,0 0,0 0)');
SET @ls2 = ST_GeomFromText('LINESTRING(0 0, 1 1)');
SELECT ST_IsValid(@ls1),ST_IsValid(@ls2);
-- 0 1
前者实际上不是线段,还是一个点