问题描述
我在 MysqL 中有一个表,其中包含我在交互式地图上显示的地理线串的各个点。其中,该表包含以下字段:
`pos` point NOT NULL,`zoom` int(10) unsigned NOT NULL
pos
包含该点的坐标,而 zoom
是一个从 1
到 20
的数字,需要加载该特定点的地图缩放级别.当地图缩小很远(低缩放级别)时,需要加载大段线,但分辨率较低(需要加载少量点)。当地图被放大(高缩放级别)时,需要加载一小部分线,但具有高分辨率。通常,这意味着该表包含的点数更高,缩放级别比低缩放级别多得多。
当用户移动或缩放地图时,当前地图视图的线点将使用如下查询加载:
SELECT * FROM LinePoints WHERE zoom <= 7 AND MBRContains(LInesTRING(POINT(4.8449,49.8804),POINT(27.0373,54.6038)),pos);
我已经在 SPATIAL
字段上添加了 pos
索引,在 BTREE
字段上添加了 zoom
索引。这适用于非常高和非常低的缩放级别:
- 在非常高的缩放级别下,边界框很小,因此仅使用空间索引选择了少量点。然后通过缩放级别过滤这少量的点很快。
- 在非常低的缩放级别下,此缩放级别仅存在少量点,因此使用
BTREE
索引。然后通过边界框过滤这少量点的速度很快。 - 然而,在中等缩放级别,它取决于 MysqL 选择的索引数据,但这两种情况都很慢。如果使用
BTREE
索引,中等缩放级别会返回很多点,并且通过边界框过滤这些点需要很长时间。如果使用空间索引,对于较大的边界框,返回的点很多,按缩放级别过滤这些点需要很长时间。在这两种情况下,查询当前在我数据库中的数据都需要几秒钟的时间,这对于交互式地图来说是不可接受的。
如何优化我的数据库?
- 有没有办法组合
SPATIAL
和BTREE
索引? - 既然缩放级别的数量是固定的,我会从以某种方式对表进行分区中受益吗?我没有尝试这个,因为 MysqL 似乎不支持包含空间列的分区表。将数据拆分到 20 个不同的表中我会受益吗?
- 切换到不同的数据库系统(例如 Postgresql)是否能够获得更好的结果?
解决方法
因为您对查询的方式有很强的把握,请从两个查询中选择一个。
SELECT * FROM LinePoints WHERE zoom <= 3
HAVING MBRContains(LINESTRING(POINT(4.8449,49.8804),POINT(27.0373,54.6038)),pos);
SELECT * FROM LinePoints
WHERE MBRContains(LINESTRING(POINT(4.8449,pos)
HAVING zoom <= 10;
(如果优化器决定将 HAVING 折叠到 WHERE 中,那么可能需要一个子查询。或者某种 IF()
函数。)