我有两张桌子,机场和跑道。
airports:
id | ident | name | latitude_deg | longitude_deg |
----------------------------------------------------------------
1 | KJFK | JFK airport NYC | 47.12345678 | 11.1234567 |
2 | KLAX | Los Angeles Intl. | 20.12345678 | 9.12345678 |
...
runways:
id | airport_ident | le_ident | length
---------------------------------------
4 | KJFK | 08/26 | 6000ft
5 | KJFK | 20/02 | 3000ft
...
我使用以下查询获取70英里范围内的所有机场(工作正常):
$output = "SELECT distinct *,
( 3959 * acos( cos( radians( 47 ) ) * cos( radians( `airports`.latitude_deg ) ) * cos( radians( `airports`.longitude_deg ) - radians( 11 ) ) + sin( radians( 47 ) ) * sin( radians( `airports`.latitude_deg ) ) ) ) AS distance
FROM `airports` HAVING distance <= 70
ORDER BY distance LIMIT 10";
当我想加入这两个表时,如何扩展查询? 我试过了:
$output = "SELECT distinct *,
( 3959 * acos( cos( radians( 47 ) ) * cos( radians( `airports`.latitude_deg ) ) * cos( radians( `airports`.longitude_deg ) - radians( 11 ) ) + sin( radians( 47 ) ) * sin( radians( `airports`.latitude_deg ) ) ) ) AS distance
FROM `airports` INNER JOIN `runways` ON `airports`.ident = `runways`.airport_ident HAVING distance <= 70
ORDER BY distance LIMIT 10";
但这会导致我的服务器崩溃。
有什么想法吗?谢谢!
答案 0 :(得分:0)
是的,该查询将与糖蜜一样慢。它必须计算整个数据库中每个可能的机场组合的距离,以便确定哪些机场的距离小于70,然后将结果减少到10个条目。它绝对会破坏数据库,并且没有任何表索引可以提供帮助。
您需要找到一种避免在WHERE
或HAVING
条款中使用计算出的距离字段的方法。
你可以轻松实现这一目标的最简单方法就是作弊。创建一个包含每个机场之间所有计算距离的表,并查询该表。距离不会改变,因此每次有人查看您的网站时都不必重新计算它们。
您需要在某个时刻对每个组合进行计算,但您只需要执行一次,并且在用户等待页面时不必进行此操作负荷。
是的,这种方法会增加您的数据库所需的存储空间,但奖励是它会使您的查询闪电般快速。
如果你想让它更快,那么使用原始lat / long字段限制连接的记录也会很有帮助。如果你想要一个70英里的半径,我们知道纬度和长度都不能超过距离源70英里,所以你可以添加它们作为过滤器;这意味着在我们开始查看实际计算的距离之前,您可以将查询过滤到140x140英里的正方形内的记录。这应该会大大减少您的查询必须搜索的记录数量,并且即使使用预先计算的距离表,也应该加快速度。