我有一个基于Rails 4的应用程序,它正在为我们处理一些SIEM风格的工作。我非常相信使代码尽可能可读,然后担心优化问题。我发现如果我依赖AR,试图找到包含一组单词的所有事件会导致性能异常,所以即使它很脆弱,我也会直接使用SQL。
使用AR有没有更好的方法来执行以下操作?
sql = "select event_id from events_words where generated>'#{starting_time.to_s(:db)}' and word_id in (select id from words where words.text in ('#{terms.join("', '")}')) group by event_id having count(distinct(word_id))=#{terms.count}"
events_words
是一个连接表,其中包含每个事件中每个字的word_id
,每个事件的event_id
和generated
,即生成事件的时间戳。生成的字段用于将搜索结果限制为时间范围,表格本身按日期分区,以使索引保持适合RAM的大小。
答案 0 :(得分:0)
为了获得更好的性能和可读性,请考虑使用JOIN操作代替IN (subquery)
。要提高可读性,请考虑限定每个列引用。
就我个人而言,我会发现这个陈述更加可读":
SELECT e.event_id
FROM events_words e
JOIN ( SELECT w.id
FROM words w
WHERE w.text IN ('#{terms.join("', '")}')
) s
ON s.id = e.word_id
WHERE e.generated > '#{starting_time.to_s(:db)}'
GROUP BY e.event_id
HAVING COUNT(DISTINCT(e.word_id))=#{terms.count}
...("可读性"根据读者快速弄清楚查询正在做什么的能力来衡量。)
至于获得像在ActiveRecord中完成的查询(如果可能的话),我倾向于怜悯那些不得不涉及破解查询实际所做的任何事情的可怜的灵魂。 / p>
修改强>
再次审核之后,我发现不需要内联视图。 (这是在我最初更改为JOIN操作期间从子查询生成的,但这并不是必需的。
这应返回相同的结果:
SELECT e.event_id
FROM events_words e
JOIN words w
ON w.id = e.word_id
WHERE e.generated > '#{starting_time.to_s(:db)}'
AND w.text IN ('#{terms.join("', '")}')
GROUP BY e.event_id
HAVING COUNT(DISTINCT(e.word_id))=#{terms.count}
答案 1 :(得分:0)
你可以试试这个:
EventWord.joins(:word).
where(:words => {:text => terms}).
where("generated > ?", :starting_time).
group(:event_id).
having("count(distinct(word_id)) = ?", terms.count).
select(:event_id)
或......
Event.joins(:word).
where(:words => {:text => terms}).
where("generated > ?", :starting_time).
group(:id).
having("count(distinct(words.id)) = ?", terms.count)