1

Linkは多くのヒット作を持つモデルを持っています。私がやろうとしているのは、データベース テーブルから 1 時間あたりのヒット数に関するデータをhits集計するyearことmonthです。dayhour

すべてが正常に機能していますが、以下のコードを実行すると、データベースで約 1,000 のクエリが発生し、かなり過剰に思えます。

#before iteration
@hits = @link.hits.group('year, month, day, hour')
  .order('year ASC, month ASC, day ASC, hour ASC')
  .select('year, month, day, hour, count(*) as hits')


#inside iteration

#Line breaks are included here for easy reading
hits_per_hour =
  @hits.where(
    :year => t.year, 
    :month => t.month,
    :day => t.day,
    :hour => t.hour
  ).map(&:hits).first || 0

これは、リンクが最初にヒットしてから 1 時間ごとに反復tするオブジェクトです。Time

レールは毎回再クエリするのではなく、クエリ結果を保存すると思います。また、クエリ結果のキャッシュなどについても何も見つけることができませんでした。私は何かを完全に見逃しているだけですか、それともこれが本当に最も簡単な方法ですか?

これは、クエリがどのように見えるかのサンプルです (これは、私のログに 1,000 個のブロックで表示されるものです)。

SELECT year, month, day, hour, count(*) as hits
FROM `hits`
WHERE
  `hits`.`link_id` = 1 AND
  `hits`.`year` = 2012 AND
  `hits`.`month` = 11 AND
  `hits`.`day` = 2 AND
  `hits`.`hour` = 14
GROUP BY year, month, day, hour
ORDER BY year ASC, month ASC, day ASC, hour ASC
4

1 に答える 1

3

Ok。つまり@hits、ActiveRecord::Relation オブジェクト (本質的には SQL クエリ) になります。各イテレーションが.where異なるパラメーターでそれを呼び出し、その結果クエリが変更されるため、Rails は 1 時間ごとにクエリを再実行する必要があると判断したと思います。

最も簡単な修正方法は、反復する前に Relation を配列に「折りたたむ」ことであり、純粋な Ruby を使用して毎回必要な結果を選択します。

@hits = @link.hits.group('year, month, day, hour')
  .order('year ASC, month ASC, day ASC, hour ASC')
  .select('year, month, day, hour, count(*) as hits').all

その後:

hits_per_hour = (@hits.select{|record| record.year == t.year && record.month == t.month && record.day == t.day && record.hour == t.hour}.map(&:hits).first || 0)

ただし、これが実際に最善の解決策である可能性は低いと思います。必要なデータとそのデータで何をしているかに応じて、データベースですべてを実行できるはずです。

于 2012-11-02T19:42:33.783 に答える