【发布时间】:2014-11-21 16:56:16
【问题描述】:
我有这两个问题:
SELECT
(ACOS(least(1,COS(0.4878295615756141)*COS(-1.4391492410217162)*COS(RADIANS(places.lat))*COS(RADIANS(places.lng))+
COS(0.4878295615756141)*SIN(-1.4391492410217162)*COS(RADIANS(places.lat))*SIN(RADIANS(places.lng))+
SIN(0.4878295615756141)*SIN(RADIANS(places.lat))))*3963.1899999999996)
AS distance, places.*
FROM `places`
WHERE ((
(ACOS(least(1,COS(0.4878295615756141)*COS(-1.4391492410217162)*COS(RADIANS(places.lat))*COS(RADIANS(places.lng))+
COS(0.4878295615756141)*SIN(-1.4391492410217162)*COS(RADIANS(places.lat))*SIN(RADIANS(places.lng))+
SIN(0.4878295615756141)*SIN(RADIANS(places.lat))))*3963.1899999999996)
<= 200.0))
和
SELECT `companies`.*
FROM `companies`
INNER JOIN `service_areas` ON `service_areas`.`company_id` = `companies`.`id`
WHERE `companies`.`id` IN (1, 3, 6, ...) AND `service_areas`.`state_name` = 'CA'
它的工作原理如下:第一个查询查找指定半径内的地点。第二个查询查找拥有第一个查询中找到的地点的所有公司。
第二个查询中的部分 - (1, 3, 6, ...) - 在 ruby 中,我从位置获取所有 company_id 并将它们放入第二个查询(company_id 是 places 表的属性)。
我试图将这两个查询合并为一个,因为我想按distance 对公司进行排序(如果离给定点最近的地方属于“公司 A”,那么这家公司将是第一个在输出中)并且作为查询的结果,我正在尝试接收:
- 在给定半径范围内拥有位置的公司
- 属于公司的地点以及这些地点都在指定的半径范围内。
这似乎有点不合我意,我正在尝试将这两个查询合并为一个,因为对于两个查询,我必须使用 Ruby 进行一些操作(以过滤位置),并且这些操作从60-90 秒...
提前感谢你们的时间。
编辑: 我稍微修改了查询,如下所示:
SELECT places.*, companies.*,
69.0 * HAVERSINE(places.lat, places.lng, 27.950575,-82.45717) AS distance
FROM places
JOIN companies ON companies.id = places.company_id
JOIN service_areas ON service_areas.company_id = companies.id
WHERE places.lat BETWEEN 27.950575 - (200.0 / 69.0)
AND 27.950575 + (200.0 / 69.0)
AND places.lng BETWEEN -82.45717 - (200.0 / (69.0 * COS(RADIANS(27.950575))))
AND -82.45717 + (200.0 / (69.0 * COS(RADIANS(27.950575))))
AND companies.id = places.company_id
AND service_areas.state_name = 'CA'
ORDER BY distance
我还在places.lat 和places.lng 列上添加了索引。当我在 MySQL 控制台中运行这个查询时,我得到了 586 个结果;查询持续了 1 分 22 秒,当我第二次运行时 30 秒,第三次尝试时 18 秒。
我只是在分析收到的结果以验证是否有我需要的结果。
EDIT2:
当我更深入地查看获取的结果时,我发现查询加载了companies,但始终没有加载places。我以为具体的搜索没有places,所以我换了城市等等,但是查询仍然返回没有places。
所以我尝试单独运行查询,如下所示:
SELECT places.*,
69.0 * HAVERSINE(places.lat,places.lng, 27.950575,-82.45717) AS distance
FROM places
WHERE places.lat
BETWEEN 27.950575 - (200 / 69.0)
AND 27.950575 + (200 / 69.0)
AND places.lng
BETWEEN -82.45717 - (200 / (69.0 * COS(RADIANS(27.950575))))
AND -82.45717 + (200 / (69.0 * COS(RADIANS(27.950575))))
此查询返回 6,600 个地点,查询持续了 30 秒。我试图在“大”查询中更改JOINs 的顺序,希望这可能会导致没有获取places,但它没有帮助,仍然没有加载places。我想知道是什么导致了这个问题。
编辑 3:
甚至尝试这样做(省略service_areas 表上的WHERE,目标是对其进行调试并找出查询从未返回任何places 的原因):
SELECT places.*,
69.0 * HAVERSINE(places.lat,places.lng, 27.950575,-82.45717) AS distance
FROM places
JOIN companies ON places.company_id = companies.id
WHERE places.lat
BETWEEN 27.950575 - (200 / 69.0)
AND 27.950575 + (200 / 69.0)
AND places.lng
BETWEEN -82.45717 - (200 / (69.0 * COS(RADIANS(27.950575))))
AND -82.45717 + (200 / (69.0 * COS(RADIANS(27.950575))))
结果是超过 5,000 家未经过滤的公司,但仍然没有位置。
谢谢
【问题讨论】:
-
该代码需要稍微清理一下。我不知道有什么东西在哪里。
-
@padagome 我同意第一个查询很难阅读,但这是因为有一些使用 RADIUS 和测角函数的计算(不知道如何提高可读性)。第二个是带有 JOIN 的“简单”查询。
-
@Padagomez - 我尽力了...
-
您的第一个查询是球余弦公式(通常称为Haversine 公式)的一个版本吗?该公式中的常数(例如
0.4878295615756141)是什么意思? ypurplaces表和第二个查询中提到的表如何相互关联? -
谢谢@PM77-1 我会看看我能从那里做些什么。
标签: mysql sql join geolocation inner-join