MySQL - 使用ORDER BY等于非常差的性能

时间:2016-07-28 09:26:35

标签: mysql

使用包含具有1.7M UK邮政编码的表的MariaDB数据库,我试图确定给定纬度和经度集的最近邮政编码,如下所示:

MariaDB [dev]> SELECT COUNT(*) as total, postcode, ( 3959 * acos( cos( radians( 53.18526 ) ) * cos( radians( latitude ) ) * cos( radians( longitude ) - radians(-3.01984) ) + sin( radians(53.18526) ) * sin( radians( latitude ) ) ) ) AS distance FROM uk_postcodes LIMIT 1;
+---------+----------+--------------------+
| total   | postcode | distance           |
+---------+----------+--------------------+
| 1751331 | AB10 1AA | 276.23821854757585 |
+---------+----------+--------------------+
1 row in set (0.35 sec)

出于本示例的目的,我添加了COUNT(*)来显示表中要开始的记录数。折扣COUNT(*)会导致查询在0.01秒内执行。

我需要获取最近的邮政编码,所以我添加ORDER BY语句:

MariaDB [dev]> SELECT postcode, ( 3959 * acos( cos( radians( 53.18526 ) ) * cos( radians( latitude ) ) * cos( radians( longitude ) - radians(-3.01984) ) + sin( radians(53.18526) ) * sin( radians( latitude ) ) ) ) AS distance FROM uk_postcodes ORDER BY distance LIMIT 1;
+----------+---------------------+
| postcode | distance            |
+----------+---------------------+
| CH5 3PF  | 0.13513453795504218 |
+----------+---------------------+
1 row in set (2.33 sec)

返回正确的结果,但需要很长时间。

Google地理编码API能够立即返回最近的邮政编码:https://maps.googleapis.com/maps/api/geocode/json?latlng=53.18526,-3.01984

如何立即从我的数据库返回结果?

2 个答案:

答案 0 :(得分:0)

以上是我在sql代码中的注释中的建议,以防它稍微提高了性能:

    SELECT postcode
, min(( 3959 * acos( cos( radians( 53.18526 ) ) * cos( radians( latitude ) ) * cos( radians( longitude ) - radians(-3.01984) ) + sin( radians(53.18526) ) * sin( radians( latitude ) ) ) )) AS distance
FROM uk_postcodes GROUP BY postcode;

答案 1 :(得分:0)

我设法解决了性能问题!

表结构

+-------------+--------------+------+-----+---------+-------+
| Field       | Type         | Null | Key | Default | Extra |
+-------------+--------------+------+-----+---------+-------+
| postcode    | varchar(8)   | NO   | PRI | NULL    |       |
| district    | varchar(4)   | YES  |     | NULL    |       |
| postal_town | varchar(35)  | YES  | MUL | NULL    |       |
| county      | varchar(37)  | YES  |     | NULL    |       |
| country     | varchar(16)  | YES  |     | NULL    |       |
| easting     | int(11)      | YES  |     | NULL    |       |
| northing    | int(11)      | YES  |     | NULL    |       |
| latitude    | decimal(7,5) | YES  |     | NULL    |       |
| longitude   | decimal(7,5) | YES  |     | NULL    |       |
| type        | varchar(14)  | YES  |     | NULL    |       |
| id          | varchar(32)  | YES  |     | NULL    |       |
| latlng      | geometry     | NO   | MUL | NULL    |       |
+-------------+--------------+------+-----+---------+-------+

空间索引

latlng字段具有空间索引,并已填充如下:

UPDATE uk_postcodes SET latlng = GeomFromText(CONCAT('POINT(',latitude,' ', longitude, ')'));

SQL QUERY

SELECT postcode, ( 3959 * acos( cos( radians( 53.18526 ) ) * cos( radians( X(latlng) ) ) * cos( radians( Y(latlng) ) - radians(-3.01984) ) + sin( radians(53.18526) ) * sin( radians( X(latlng) ) ) ) ) AS distance
FROM uk_postcodes
WHERE MBRContains
(LineString
  (
    Point (53.18526 + 10 / (111.1 / COS(RADIANS(53.18526))), -3.01984 + 10 / 111.1),
    Point (53.18526 - 10 / (111.1 / COS(RADIANS(53.18526))), -3.01984 - 10 / 111.1)
  ),
  latlng
)
ORDER BY distance
LIMIT 1;

RESULT

+----------+---------------------+
| postcode | distance            |
+----------+---------------------+
| CH5 3PF  | 0.13513453795504218 |
+----------+---------------------+
1 row in set (0.00 sec)