我有两个模型对象:
- 事件
- 场地
活动有场地。场地可以有 1..* 事件。
场地有一个位置,一个经纬度,我使用 Geokit Rails 插件。以下是这些模型在 Rails 中的样子:
class Event < ActiveRecord::Base
belongs_to :venue
acts_as_mappable :through => :venue
end
和
class Venue < ActiveRecord::Base
has_many :events
acts_as_mappable
end
非常简单!现在,我想运行一个查询,我想查找某个区域几英里内的所有事件,查看 Geokit API,我发现我可以使用可映射的:通过事件关联,并且应该能够在 Event 上调用 geokit finder!非常好(所以你可以在上面看到,我已经添加了acts_as_mappable :through 到事件中)。
这是我的 ActiveRecord 查询:
Event.find(:all, :origin => [lat, lng], :select => 'title', :within => 5, :limit => 10)
这是生成的 SQL:
SELECT `events`.`id` AS t0_r0, `events`.`title` AS t0_r1, `events`.`description` AS t0_r2,
`events`.`created_at` AS t0_r3, `events`.`updated_at` AS t0_r4, `events`.`venue_id` AS
t0_r5, `events`.`event_detail_id` AS t0_r6, `events`.`event_detail_type` AS t0_r7,
`venues`.`id` AS t1_r0, `venues`.`name` AS t1_r1, `venues`.`lat` AS t1_r2, `venues`.`lng`
AS t1_r3, `venues`.`created_at` AS t1_r4, `venues`.`updated_at` AS t1_r5 FROM `events` LEFT
OUTER JOIN `venues` ON `venues`.id = `events`.venue_id WHERE
(((venues.lat>51.4634898826039 AND venues.lat>51.5533406301823 AND venues.lng>-
0.197713629915149 AND venues.lng<-0.053351862714855)) AND
((ACOS(least(1,COS(0.898991438708539)*COS(-0.00219095974226756)*COS(RADIANS(venues.lat))*COS(RADIANS(venues.lng))
COS(0.898991438708539)*SIN(-
0.00219095974226756)*COS(RADIANS(venues.lat))*SIN(RADIANS(venues.lng))
SIN(0.898991438708539)*SIN(RADIANS(venues.lat))))*6376.77271)
<= 5)) LIMIT 10
哎哟。好吧,这需要相当长的时间来运行,而且不仅仅是数学问题,我认为这里的性能存在很大问题,这需要 2 秒才能在我的桌面上运行!但归根结底,这是我的抱怨:
- 为了尝试提高性能,您可以看到我尝试在我的 ActiveRecord 查找查询中使用 SELECT 语句。我只想知道匹配的这些事件的标题,而不是所有其他字段。但是查询通过了,并从 Event! 中选择了所有内容!它使用我不熟悉的奇怪别名,例如“t1_r1”。所以这显然是一个问题。
此外,当单独针对场地运行(即取消 JOIN)时,此查询在不到 10 毫秒内执行。那么有没有办法先进行场地搜索,然后针对事件进行加入?我认为连接必须在两个表上作为一个整体完成,然后地理编码部分才会进入并缩小数据集。
任何有助于加强这个问题的帮助将不胜感激(这是一个非商业项目)。我觉得模型很简单我应该可以不用大惊小怪地做到这一点?
提前致谢!
(编辑:在这篇文章的早期版本中,我很愚蠢,Limit 工作得很好,我的观点被打破了,编辑删除了那部分。)