数据库:查询地理位置数据的最佳性能方式?
我有一个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