问题:查找给定纬度/经度的办公室列表
MySQL版本:我们目前正在使用5.5.1
表架构:
mysql> describe delivery_office;
+-------------------------------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------------------------------+--------------+------+-----+---------+-------+
| id | bigint(20) | NO | PRI | NULL | |
| address_1 | varchar(255) | YES | | NULL | |
| address_2 | varchar(255) | YES | | NULL | |
| address_3 | varchar(255) | YES | | NULL | |
| address_4 | varchar(255) | YES | | NULL | |
| latitude | double | YES | MUL | NULL | |
| longitude | double | YES | | NULL | |
| name | varchar(255) | YES | | NULL | |
| postcode | varchar(255) | YES | | NULL | |
| pt_loca | point | NO | MUL | NULL | |
+-------------------------------+--------------+------+-----+---------+-------+
表索引:
mysql> show index from delivery_office;
+---------------------+------------+--------------+--------------+----------------------------+-----------+-------------+----------+--------+------+------------+---------+- --------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+---------------------+------------+--------------+--------------+----------------------------+-----------+-------------+----------+--------+------+------------+---------+- --------------+
| delivery_office | 0 | PRIMARY | 1 | id | A | 2156 | NULL | NULL | | BTREE | | |
| delivery_office | 1 | geo_index | 1 | latitude | A | 1896 | NULL | NULL | YES | BTREE | | |
| delivery_office | 1 | geo_index | 2 | longitude | A | 1939 | NULL | NULL | YES | BTREE | | | | | |
| delivery_office | 1 | pt_loca2 | 1 | pt_loca | A | 2156 | 32 | NULL | | SPATIAL | | |
+---------------------+------------+--------------+--------------+----------------------------+-----------+-------------+----------+--------+------+------------+---------+- --------------+
解决方案:使用地理位置查询来查找它。
我使用了以下解决方案,但两者都会导致全表扫描。
我的表只有2168条记录。
Fastest Way to Find Distance Between Two Lat/Long Points
mysql> explain SELECT *
-> FROM delivery_office
-> WHERE MBRContains
-> (
-> LineString
-> (
-> Point (
-> 51.5177 + 1 / 111.1,
-> -0.0968 + 1 / ( 111.1 /COS(RADIANS(51.5177)))
->
-> ),
-> Point (
-> 51.5177 - 1 / 111.1,
-> -0.0968 - 1 / ( 111.1 / COS(RADIANS(51.5177)))
->
-> )
-> ),
-> GeomFromText('POINT(51.5177 -0.0968)')
-> );
+----+-------------+---------------------+------------+------+----- ----------+------+---------+------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+---------------------+------------+------+---------------+------+---------+------+------+----------+-------+
| 1 | SIMPLE | delivery_office | NULL | ALL | NULL | NULL | NULL | NULL | 2156 | 100.00 | NULL |
+----+-------------+---------------------+------------+------+------ ---------+------+---------+------+------+----------+-------+
1 row in set, 2 warnings (0.00 sec)
https://gis.stackexchange.com/questions/31628/find-points-within-a-distance-using-mysql
mysql> explain EXTENDED SELECT (
-> 3959 * acos (
-> cos ( radians(51.3191750) )
-> * cos( radians( latitude ) )
-> * cos( radians( longitude ) - radians(-0.5632660) )
-> + sin ( radians(51.3191750) )
-> * sin( radians( latitude ) )
-> )
-> ) AS distance_in_miles, delivery_office.*
-> FROM delivery_office
-> HAVING distance_in_miles < 10
-> ORDER BY distance_in_miles
-> LIMIT 0 , 30;
+----+-------------+---------------------+------------+------+---------------+------+---------+------+------+----------+-----------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+---------------------+------------+------+---------------+------+---------+------+------+----------+-----------------------------+
| 1 | SIMPLE | delivery_office | NULL | ALL | NULL | NULL | NULL | NULL | 2156 | 100.00 | Using where; Using filesort |
+----+-------------+---------------------+------------+------+---------------+------+---------+------+------+----------+-----------------------------+
1 row in set, 2 warnings (0.00 sec)
是否可以触发不会导致全表扫描的查询。
答案 0 :(得分:0)
正如@RickJames所建议的那样,我可以使用此处提供的解决方案来优化查询:
https://www.scribd.com/presentation/2569355/Geo-Distance-Search-with-MySQL https://blog.fedecarg.com/2009/02/08/geo-proximity-search-the-haversine-equation/
以下是使用此优化的结果,行扫描从全表扫描减少到181条记录:
mysql> SELECT (
-> 3959 * acos (
-> cos ( radians(51.3191750) )
-> * cos( radians( latitude ) )
-> * cos( radians( longitude ) - radians(-0.5632660) )
-> + sin ( radians(51.3191750) )
-> * sin( radians( latitude ) )
-> )
-> ) AS distance_in_miles
-> FROM delivery_office
-> where longitude between (-0.5632660 - 10/abs(cos(radians(51.3191750))*69)) and (-0.5632660 + 10/abs(cos(radians(51.3191750))*69)) and latitude between (51.3191750 - (10/69)) and (51.3191750 + (10/69))
-> HAVING distance_in_miles < 10
-> ORDER BY distance_in_miles
-> LIMIT 0 , 10;
+--------------------+
| distance_in_miles |
+--------------------+
| 0.3381472408327969 |
| 1.9060143092544148 |
| 2.840055550183541 |
| 3.2969844240913697 |
| 3.356363831356166 |
| 4.815726191392366 |
| 5.134370232935941 |
| 5.177268204112493 |
| 5.528244889409913 |
| 5.702281140258665 |
+--------------------+
10 rows in set (0.00 sec)
mysql> explain EXTENDED SELECT ( -> 3959 * acos (
-> cos ( radians(51.3191750) )
-> * cos( radians( latitude ) )
-> * cos( radians( longitude ) - radians(-0.5632660) )
-> + sin ( radians(51.3191750) )
-> * sin( radians( latitude ) )
-> )
-> ) AS distance_in_miles
-> FROM delivery_office
-> where longitude between (-0.5632660 - 10/abs(cos(radians(51.3191750))*69)) and (-0.5632660 + 10/abs(cos(radians(51.3191750))*69)) and latitude between (51.3191750 - (10/69)) and (51.3191750 + (10/69))
-> HAVING distance_in_miles < 10
-> ORDER BY distance_in_miles
-> LIMIT 0 , 10;
+----+-------------+---------------------+------------+-------+---------------+-----------+---------+------+------+----------+------------------------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+---------------------+------------+-------+---------------+-----------+---------+------+------+----------+------------------------------------------+
| 1 | SIMPLE | delivery_office | NULL | range | geo_index | geo_index | 18 | NULL | 181 | 11.11 | Using where; Using index; Using filesort |
+----+-------------+---------------------+------------+-------+---------------+-----------+---------+------+------+----------+------------------------------------------+
1 row in set, 2 warnings (0.00 sec)