我正在使用MariaDB 10.1.16,我有一个包含170万英国邮政编码的表格,用于位置自动完成,地理编码和反向地理编码。
下面是表格结构:
return
(from x in dbcontext.table1
where Age == null || x.age==Age
&& Gender == null || x.gender == Gender
select new model{
model properties here..
}).ToList();
查询表中的单个邮政编码会立即返回结果:
+-------------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------------+--------------+------+-----+---------+-------+
| postcode | varchar(8) | NO | PRI | NULL | |
| district | varchar(4) | YES | | NULL | |
| postal_town | varchar(35) | YES | | 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 | |
+-------------+--------------+------+-----+---------+-------+
但是我现在想用我当前的位置找到最近的邮政编码。
我的大概位置是:MariaDB [dev]> SELECT * FROM uk_postcodes WHERE postcode = "CH5 3NS";
+----------+----------+-------------+--------+---------+---------+----------+----------+-----------+------------+----------------------------------+
| postcode | district | postal_town | county | country | easting | northing | latitude | longitude | type | id |
+----------+----------+-------------+--------+---------+---------+----------+----------+-----------+------------+----------------------------------+
| CH5 3NS | CH5 | Hawarden | Clwyd | Wales | 331718 | 365725 | 53.18422 | -3.02325 | Geographic | f99a64139bfb8cf8091ca870808b355b |
+----------+----------+-------------+--------+---------+---------+----------+----------+-----------+------------+----------------------------------+
1 row in set (0.00 sec)
我的查询:
53.1852582, -3.0198408999999997
虽然结果是正确的,但是花了太长时间。但为什么呢?
答案 0 :(得分:0)
这个答案不太清楚为什么它如此慢(在订购之前计算数据库中每一行的值),但可能是一个快速的黑客来减少要检查的行数:
当您将纬度/经度值限制为附近的值时,您可以限制计算距离所需的数据范围。 (来自these slides的公式(第12ff页)当您按里程计算时,此方法有效...否则您必须使用正确的公里数值调整“69”。
return
然后你修改你的查询:
1° of latitude ~= 69 miles
1° of longitude ~= cos(latitude)*69
使用前面提到的经过计算的经度/纬度。
这样可以提高整体速度,而无需更改数据库结构。
答案 1 :(得分:0)
我设法解决了性能问题!
$result= DB::table('a')->whereIn('cid', [1,2,3,4]);
latlng字段具有空间索引,并已填充如下:
+-------------+--------------+------+-----+---------+-------+
| 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 | |
+-------------+--------------+------+-----+---------+-------+
UPDATE uk_postcodes SET latlng = GeomFromText(CONCAT('POINT(',latitude,' ', longitude, ')'));
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;