在MySQL中使用空间索引时性能不佳


13

重新建议在Stack Overflow上提出的一个问题,这是一个更好的论坛。

我正在尝试进行一些实验,以推动不是地理空间但非常适合的数据集,并且发现结果有些令人不安。数据集是基因组数据,例如人类基因组,其中我们有一个DNA区域,其中诸如基因之类的元素占据特定的起始和终止坐标(我们的X轴)。我们有多个占据Y轴的DNA(染色体)区域。目标是带回沿单个Y坐标与两个X坐标相交的所有项目,例如LineString(START 1,END 2)。

该理论听起来很合理,所以我将其推入了现有的基于MySQL的基因组项目中,并提出了一个表结构,如下所示:

CREATE TABLE `spatial_feature` (
  `spatial_feature_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `external_id` int(10) unsigned NOT NULL,
  `external_type` int(3) unsigned NOT NULL,
  `location` geometry NOT NULL,
  PRIMARY KEY (`spatial_feature_id`),
  SPATIAL KEY `sf_location_idx` (`location`)
) ENGINE=MyISAM;

external_id表示我们已编码到该表中的实体的标识符并对其进行编码external_type。一切看起来都很不错,我输入了一些初步的数据(30,000行),这些数据似乎运行良好。当它增加到超过300万行标记时,MySQL拒绝使用空间索引,并且在强制使用空间索引时速度较慢(40秒与使用全表扫描的5秒相比)。当添加更多数据时,该索引开始使用,但性能损失仍然存在。强制关闭索引可使查询降低到8秒。我正在使用的查询看起来像:

select count(*)
from spatial_feature
where MBRIntersects(GeomFromText('LineString(7420023 1, 7420023 1)'), location);

沿Y方向输入的数据非常密集(想像一下,就像您已经记录了每条建筑物,电话亭,邮政信箱和鸽子在很长路上的位置一样)。我已经测试了R-Indexes在Java中如何处理此数据,以及该领域中的其他人已成功将它们应用于平面文件格式。但是,没有人将它们应用于数据库AFAIK,这是此测试的目标。

向沿特定轴并不是完全不同的空间模型添加大量数据时,有没有人看到过类似的行为?如果我反转坐标用法,问题仍然存在。如果这是原因,我正在运行以下设置

  • MacOS 10.6.6
  • MySQL 5.1.46

Answers:


5

MySQL与PostGIS一样,将其空间索引数据存储在R树结构中,以便可以快速找到内容。与B树一样,R树的组织方式也经过了优化,使其仅用于检索表中总数据的一小部分。实际上,对于需要读取表的较大部分以返回数据或执行巨大联接的查询,忽略索引的速度更快,这是一个经典案例,这引起了许多数据库论坛的关注[海报]抱怨查询返回了一半的查询表“不使用他们刚刚创建的新索引”。

来自 http://rickonrails.wordpress.com/2009/03/30/big-ole-mysql-spatial-table-optimization-tricks/

如果您可以将所有表数据放入内存中,则性能会很好。如果/当您需要开始进行磁盘读取时,性能会很快变差。在两种情况下,您是否正在执行mysql实例的内存使用模式:30k行与3000k行?


我认为这可能更接近问题。TBH是我想要的R指数;其他空间数学是一个不错的选择,因为这必须在旧系统下的API层中完成。我确实尝试了一些调优,但是增加键缓冲区并没有帮助(其他缓冲区在这里像表缓冲区一样无济于事,因为它在我的个人服务器上是1个表查询)。奇怪的是,MySQL在运行查询时将我的机器砸在地上(在查询运行期间100%)。那就是说它进行了全表扫描,所以也许并不奇怪
andeyatz 2011年

5

您的mysql安装或.ini设置一定有问题。刚刚在我的旧Mac(10.6.8 / MySQL 5.2)上测试了地理空间索引。该配置与您的配置相似,我测试了大型地理数据转储(900万条记录)。我做了这个查询:

SET @radius = 30;
SET @center = GeomFromText('POINT(51.51359 7.465425)');
SET @r = @radius/69.1;
SET @bbox = CONCAT('POLYGON((', 
  X(@center) - @r, ' ', Y(@center) - @r, ',', 
  X(@center) + @r, ' ', Y(@center) - @r, ',', 
  X(@center) + @r, ' ', Y(@center) + @r, ',', 
  X(@center) - @r, ' ', Y(@center) + @r, ',', 
  X(@center) - @r, ' ', Y(@center) - @r, '))' 
);

SELECT geonameid, SQRT(POW( ABS( X(point) - X(@center)), 2) + POW( ABS(Y(point) - Y(@center)), 2 ))*69.1 
AS distance
FROM TABLENAME AS root
WHERE Intersects( point, GeomFromText(@bbox) ) 
AND SQRT(POW( ABS( X(point) - X(@center)), 2) + POW( ABS(Y(point) - Y(@center)), 2 )) < @r 
ORDER BY distance; 

仅用了0.0336秒。

我确实使用上面的查询,例如,用于表之间的比较,其中仅@center的lat / lng值来自的表具有来自city_latitude / city_longitude和9-12 Mio的普通索引。geonames.org的表格具有地理空间索引。

我只是想补充一点,当任何人在表中插入大数据时,在INSERT之后添加索引的性能可能更高。如果没有,添加的每一行都将花费更长的时间... [但这并不重要]


哇,真的很好。现在,我不确定自己的测试中做错了什么。与更传统的地理空间数据集相比,可能引起问题的一件事是我的数据集的性质。就是说,我只是猜测,没有任何依据。很高兴看到您不需要强制索引进入内存就可以提高速度。
andeyatz 2013年

具有半径的WHERE子句可能使用索引过滤掉了表格的大部分内容。
tmarthal

2

您是否考虑过将其分为两个1D列而不是单个2D列?

优化器可能会阻塞所有相似的数据,而拥有两列变化更大的列可能会有所帮助。

您可能还要检查的是检查项目的顺序。我在Oracle Spatial中遇到一个问题,该问题是我在“姓氏”和IN_REGION过滤器上进行搜索。Oracle决定最快的方法是使用姓氏,然后进行区域检查。让我告诉你,对克利夫兰的所有鲁滨逊的区域进行检查的速度。我记得我必须传递一个Oracle特定的参数来强制它首先使用空间索引。


不幸的是,一维的人口远远少于另一维。为了说明这一点,人类基因组具有24个独特的染色体(22对和两个性染色体),以及一袋数据,这些数据已组装到不同的水平。这意味着,如果您将元素映射到基本用例,则一维中只有24个唯一标识符。最初的希望是,R树索引不仅能够执行性能更高的重叠范围检查,而且还能在单个查询中区分这些区域。
andeyatz 2011年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.