数据库:查询地理位置数据的最佳性能方式?

我有一个MySQL数据库。 我将数据库存储在数据库中,并且只对数据库执行1个查询, 但是我需要这个查询以超快的速度执行 ,这就是返回一个方框中的所有家庭的地理纬度和经度。

SELECT * FROM homes WHERE geolat BETWEEN ??? AND ??? AND geolng BETWEEN ??? AND ??? 

如何最好的方式来存储我的地理数据,以便我可以执行此查询显示地理定位框中最快的所有家庭?

基本上:

  • 我使用最好的SQL语句执行此查询最快?
  • 有没有其他方法存在,可能甚至不使用数据库,我查询盒装地理位置范围内的家园的结果最快的方式?

万一它有帮助,我已经包括我的数据库表架构如下:

 CREATE TABLE IF NOT EXISTS `homes` ( `home_id` int(10) unsigned NOT NULL auto_increment, `address` varchar(128) collate utf8_unicode_ci NOT NULL, `city` varchar(64) collate utf8_unicode_ci NOT NULL, `state` varchar(2) collate utf8_unicode_ci NOT NULL, `zip` mediumint(8) unsigned NOT NULL, `price` mediumint(8) unsigned NOT NULL, `sqft` smallint(5) unsigned NOT NULL, `year_built` smallint(5) unsigned NOT NULL, `geolat` decimal(10,6) default NULL, `geolng` decimal(10,6) default NULL, PRIMARY KEY (`home_id`), KEY `geolat` (`geolat`), KEY `geolng` (`geolng`), ) ENGINE=InnoDB ; 

UPDATE

我理解地球曲率中的空间因素,但我最感兴趣的是返回最快的地理数据。 除非这些空间数据库包以某种方式更快地返回数据,否则不build议使用空间扩展。 谢谢

更新2

请注意,下面没有人真正回答了这个问题。 我真的很期待我可能得到的任何帮助。 提前致谢。

这里有一篇关于MySQL地理定位性能的好文章。

编辑很确定这是使用固定的半径。 另外,我并不是100%确定用于计算距离的algorithm是最先进的(即它将通过地球“钻取”)。

最重要的是该algorithm是很便宜的给你一个行数限制球场做适当的距离search。

我有同样的问题,并写了一个3部分的博客post。 这比地理索引快。

简介 , 基准 , SQL

我用过的一个技巧是创造一个四舍五入的区域。 也就是说,如果您的位置在36.12345,-120.54321,并且您想将其与位于半英里(近似)网格框内的其他位置分组,则可以将其区域称为36.12x-120.54,并且所有其他具有相同四舍五入区域的位置将落入同一个框中。

显然,这不会让你有一个干净的半径,即如果你正在看的位置比另一个更接近于一个边缘。 但是,通过这种设置,计算围绕您的主要位置框的八个框很容易。 以机智:

 [36.13x-120.55][36.13x-120.54][36.13x-120.53] [36.12x-120.55][36.12x-120.54][36.12x-120.53] [36.11x-120.55][36.11x-120.54][36.11x-120.53] 

把所有的位置都用匹配的舍入标签拉出来,然后一旦把它们从数据库中拿出来,就可以进行距离计算来决定使用哪一个。

如果您确实需要提高性能,可以为数据定义边界框,并在插入时将预计算边界框映射到您的对象,并稍后用于查询。

如果结果集相当小,您仍然可以在应用程序逻辑中进行精度修正(比数据库更容易缩放水平),同时能够提供准确的结果。

看看Bret Slatkin的geobox.py ,其中包含了很好的文档。

如果你打算在可预见的将来做更复杂的查询,我仍然会推荐检查PostgreSQL和PostGIS与MySQL的比较。

您使用的索引确实是B树索引,并支持查询中的BETWEEN关键字。 这意味着优化器能够使用您的索引来查找“盒子”中的房屋。 然而这并不意味着它会一直使用这些指数。 如果您指定一个包含太多“命中”的范围,则不会使用索引。

这看起来很快。 我唯一担心的是它会使用一个索引来获取纬度3英里以内的所有值,然后在距离经度3英里范围内对这些值进行过滤。 如果我理解底层系统是如何工作的,那么每个表只能使用一个INDEX,所以lat或long的索引是没有价值的。

如果你有大量的数据,它可能会加快速度,给每一个1×1平方英里一个唯一的逻辑ID,然后对SELECT做一个额外的限制(area =“23234/34234”OR area =“23235/34234 “或…),然后强制数据库使用该索引而不是lat和long。 那么你只会过滤less得多平方英里的数据。

公寓? 你甚至可能不会有一万个。 只需使用像STRTree一样的内存中索引。

坚持你目前的做法有一个你应该做的改变,而不是分别索引geolat和geolong你应该有一个综合指数:

 KEY `geolat_geolng` (`geolat`, `geolng`), 

目前你的查询只会利用两个索引中的一个。

MongoDB及其地理空间索引是一个很好的select。

您可能会考虑创build一个单独的表“GeoLocations”,其中包含('geolat','geolng')的主键,并且如果该特定地理位置恰好有一个家,则会有一个保存home_id的列。 这应该允许优化器search将在磁盘上sorting以获得home_ids列表的一系列地理位置。 然后,您可以使用“家庭”表执行join,以查找有关这些home_ids的信息。

 CREATE TABLE IF NOT EXISTS `GeoLocations` ( `geolat` decimal(10,6) NOT NULL, `geolng` decimal(10,6) NOT NULL, `home_id` int(10) NULL PRIMARY KEY (`geolat`,`geolng`) ); SELECT GL.home_id FROM GeoLocations GL INNER JOIN Homes H ON GL.home_id = H.home_id WHERE GL.geolat between X and Y and GL.geolng between X and Y