在我的表中,我有大约300万条记录。 当我运行此查询时,获取计数值需要大约15-30秒
SELECT COUNT(*) AS `neighbours_count` FROM house
WHERE
( 6371 *
acos(
cos( radians( "48.70877900" ) ) *
cos( radians( `map_y` ) ) * cos( radians( `map_x` ) -
radians( "37.49893200" ) ) + sin( radians( "48.70877900" )
)
* sin( radians( `map_y` ) ) )
) <= 0.3
查询本身会计算特定坐标300米范围内的建筑物。 6371是地球半径,其余部分是公式计算接近坐标的公式。
查询解释:
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE house ALL NULL NULL NULL NULL 2442710 Using where
创建声明:
CREATE TABLE IF NOT EXISTS `house` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`country_id` int(11) NOT NULL,
`state_id` int(11) NOT NULL,
`city_id` int(11) NOT NULL,
`street_id` int(11) NOT NULL,
`name` varchar(250) NOT NULL,
`map_x` decimal(11,8) NOT NULL,
`map_y` decimal(11,8) NOT NULL,
UNIQUE KEY `id` (`id`),
KEY `country_id` (`country_id`),
KEY `city_id` (`city_id`),
KEY `street_id` (`street_id`),
KEY `map_x` (`map_x`),
KEY `map_y` (`map_y`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT='map_y - latitude, map_x - longitude' AUTO_INCREMENT=2442769 ;
请给我一个如何优化此查询的建议。
答案 0 :(得分:0)
真正优化查询的方法很少。一种方法是添加其他条件:
where (max_x between A and B and max_y between C and D) and
. . .
问题在于您无法在max_y
和max_x
上使用索引。一种变化是在每侧施加300米的网格并将每个点移动到最近的网格点。这实现起来有点痛苦(需要触发器或类似的东西)。但是你知道你的状况意味着相邻的网格点上的东西。所以,像这样:
where (grid_x, grid_y) in ((grid_A-1, grid_B), (grid_A-1, grid_B-1), (grid_A-1, grid_B+1),
(grid_A, grid_B), (grid_A, grid_B-1), (grid_A, grid_B+1),
(grid_A+1, grid_B), (grid_A+1, grid_B-1), (grid_A+1, grid_B+1)
) and
. . .
这可以使用grid_x, grid_y
上的索引 - 我想。如果没有,您可以使用union all
获得相同的效果。
真的,最好的选择是geospatial extensions。 GIS查询使用来自典型关系数据库数据的不同数据结构,这就是需要扩展的原因。
答案 1 :(得分:0)
这是一个困难的答案。也许,我会尝试:
mysql> describe web_admin_roles;
+----------------------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------------------+-------------+------+-----+---------+-------+
| roleIdentity | varchar(64) | NO | PRI | NULL | |
| addNewAdmin | bit(1) | YES | | NULL | |
| viewAdmin | bit(1) | YES | | NULL | |
| modifyAdmin | bit(1) | YES | | NULL | |
| removeAdmin | bit(1) | YES | | NULL | |
| approveUser | bit(1) | YES | | NULL | |
| viewUser | bit(1) | YES | | NULL | |
| modifyUser | bit(1) | YES | | NULL | |
| removeUser | bit(1) | YES | | NULL | |
| addFacility | bit(1) | YES | | NULL | |
| viewFacility | bit(1) | YES | | NULL | |
| modifyFacility | bit(1) | YES | | NULL | |
| removeFacility | bit(1) | YES | | NULL | |
| addManager | bit(1) | YES | | NULL | |
| viewManager | bit(1) | YES | | NULL | |
| modifyManager | bit(1) | YES | | NULL | |
| removeManager | bit(1) | YES | | NULL | |
| isSuperAdmin | bit(1) | NO | | NULL | |
| createdTimeMilliSecs | bigint(20) | NO | | NULL | |
| updatedTimeMilliSecs | bigint(20) | YES | | NULL | |
| isRecordActive | int(11) | NO | | NULL | |
+----------------------+-------------+------+-----+---------+-------+
,1次致电radians( "48.70877900" )
)。如果可能的话,我会尝试更改这些常量值的调用。radians( "37.49893200" )
我希望你会发现它有用
PD:尝试
abs( map_x - origin_x ) > MAX_X_DISTANCE