我正在使用CodeIgniter 2,在我的数据库模型中,我有一个查询,它根据与给定地理位置的距离连接两个表并过滤行。
SELECT users.id,
(3959 * acos(cos(radians(42.327612)) *
cos(radians(last_seen.lat)) * cos(radians(last_seen.lon) -
radians(-77.661591)) + sin(radians(42.327612)) *
sin(radians(last_seen.lat)))) AS distance
FROM users
JOIN last_seen ON users.id = last_seen.seen_id
WHERE users.age >= 18 AND users.age <= 30
HAVING distance < 50
我不确定distance
是否会使此查询花费的时间特别长。我的users table
中确实有超过300,000行。我last_seen
表中的金额相同。我确信它会发挥作用。
但是,users表中的age
列与id
列一起编入索引。
lat
表格中的lon
和last_seen
列也会被编入索引。
有没有人知道为什么这个查询需要这么长时间以及如何改进它?
更新
事实证明,这个查询实际上运行得非常快。当我在PHPMyAdmin中执行此查询时,需要0.56秒。还不错。但是,当我尝试使用像SequelPro这样的第三方SQL客户端执行此查询时,至少需要20秒,而我的mac上的所有其他应用程序都会变慢。当通过jQuery的load()
方法加载脚本来执行查询时,它需要大约相同的时间。
在Google Chrome的开发者工具中查看我的网络标签后,加载这么长时间的原因似乎是因为所谓的TTFB
或时间到第一个字节。这是永远的。
答案 0 :(得分:1)
为了使此查询更快,您需要在实际计算每个和每个上的距离之前使用索引来限制行数。为此,您可以根据纬度/经度和所需距离的粗略公式限制last_seen
的行。
这个想法是,如果经度与参考经度相距一定距离,那么纬度与参考纬度相同的位置将在50英里距离内,反之亦然。 对于50英里的距离,RefLat + -1和RefLon + -1将是在实际计算精确距离之前限制行的良好开端。
last_seen.lat BETWEEN 42.327612 - 1 AND 42.327612 + 1
AND last_seen.lon BETWEEN -77.661591 - 1 AND -77.661591 + 1
答案 1 :(得分:0)
对于此查询:
SELECT users.id, (3959 * acos(cos(radians(42.327612)) * cos(radians(last_seen.lat)) * cos(radians(last_seen.lon) - radians(-77.661591)) + sin(radians(42.327612)) * sin(radians(last_seen.lat)))) AS distance
FROM users JOIN
last_seen
ON users.id = last_seen.seen_id
WHERE users.age >= 18 AND users.age <= 30
HAVING distance < 50;
最佳指数为users(age, id)
和last_seen(seen_id)
。不幸的是,距离计算需要一段时间,因为必须为每一行计算距离。您可能需要考虑使用MySQL的GIS扩展来帮助进行此类查询。