0

2 つの日付の間のすべてのオブジェクトを返す単純な Rails API を作成しました。Rails コンソールでは、データベースは 1 回だけクエリされますが、API は同じリクエストに対して複数のクエリを引き起こします。

これはコントローラーメソッドです:

def historic_returns
  respond_to do |format|
    format.json do
      start_date = Date.new(params[:start_year].to_i, params[:start_month].to_i)
      end_date = Date.new(params[:end_year].to_i, params[:end_month].to_i)
      @result = ShillerDataMonth.records_between_two_dates(start_date, end_date)
      render :json => @result
    end
  end
end

これは、コントローラーが使用するモデルのクラス メソッドです。

def self.records_between_two_dates(start_date, end_date)
  ShillerDataMonth.where("record_date >= ? AND record_date <= ?", start_date, end_date).order("record_date asc")
end

Rails コンソールで ShillerDataMonth#records_between_two_dates メソッドを実行すると、予想どおり、データベース クエリは 1 つしかありません。

>> ShillerDataMonth.records_between_two_dates(Date.new(2010, 01), Date.new(2012, 01))
  ShillerDataMonth Load (2.2ms)  SELECT "shiller_data_months".* FROM "shiller_data_months" WHERE (record_date >= '2010-01-01' AND record_date <= '2012-01-01') ORDER BY record_date asc

ただし、localhost /historic_returns.json?start_year=2010&start_month=1&end_year=2012&end_month=1 でこのパスにアクセスすると、複数のクエリがあります。

Started GET "/historic_returns.json?start_year=2010&start_month=1&end_year=2012&end_month=1" for 127.0.0.1 at 2013-07-08 20:44:34 -0400
Processing by ShillerDataMonthsController#historic_returns as JSON
  Parameters: {"start_year"=>"2010", "start_month"=>"1", "end_year"=>"2012", "end_month"=>"1"}
  ShillerDataMonth Load (2.1ms)  SELECT "shiller_data_months".* FROM "shiller_data_months" WHERE (record_date >= '2010-01-01' AND record_date <= '2012-01-01') ORDER BY record_date asc
  ShillerDataMonth Load (0.6ms)  SELECT "shiller_data_months".* FROM "shiller_data_months" WHERE "shiller_data_months"."year_month" = '2009.12' LIMIT 1
  CACHE (0.0ms)  SELECT "shiller_data_months".* FROM "shiller_data_months" WHERE "shiller_data_months"."year_month" = '2009.12' LIMIT 1
  CACHE (0.0ms)  SELECT "shiller_data_months".* FROM "shiller_data_months" WHERE "shiller_data_months"."year_month" = '2009.12' LIMIT 1
  CACHE (0.0ms)  SELECT "shiller_data_months".* FROM "shiller_data_months" WHERE "shiller_data_months"."year_month" = '2009.12' LIMIT 1
  ShillerDataMonth Load (0.6ms)  SELECT "shiller_data_months".* FROM "shiller_data_months" WHERE "shiller_data_months"."year_month" = '2010.01' LIMIT 1
  CACHE (0.0ms)  SELECT "shiller_data_months".* FROM "shiller_data_months" WHERE "shiller_data_months"."year_month" = '2010.01' LIMIT 1
  CACHE (0.0ms)  SELECT "shiller_data_months".* FROM "shiller_data_months" WHERE "shiller_data_months"."year_month" = '2010.01' LIMIT 1
  CACHE (0.0ms)  SELECT "shiller_data_months".* FROM "shiller_data_months" WHERE "shiller_data_months"."year_month" = '2010.01' LIMIT 1
  ShillerDataMonth Load (0.8ms)  SELECT "shiller_data_months".* FROM "shiller_data_months" WHERE "shiller_data_months"."year_month" = '2010.02' LIMIT 1
  CACHE (0.0ms)  SELECT "shiller_data_months".* FROM "shiller_data_months" WHERE "shiller_data_months"."year_month" = '2010.02' LIMIT 1
  CACHE (0.0ms)  SELECT "shiller_data_months".* FROM "shiller_data_months" WHERE "shiller_data_months"."year_month" = '2010.02' LIMIT 1
  CACHE (0.0ms)  SELECT "shiller_data_months".* FROM "shiller_data_months" WHERE "shiller_data_months"."year_month" = '2010.02' LIMIT 1

...これが毎月続きます....

API に複数のリクエストがあるのはなぜですか? どうすれば修正できますか?助けてくれてありがとう!

4

2 に答える 2

0

Rails コンソールでいくつかの実験を行ったところ、to_json が不要なデータベース クエリが非常に多く作成された理由のようです。Rails コンソールでは、 to_json コマンドは、すべての不要なクエリが生成される場所です。

@result = ShillerDataMonth.records_between_two_dates(Date.new(2012, 1), Date.new(2013, 1))
  ShillerDataMonth Load (6.5ms)  SELECT "shiller_data_months".* FROM "shiller_data_months" WHERE (record_date >= '2012-01-01' AND record_date <= '2013-01-01') ORDER BY record_date asc
>> @result.to_json #multiple queries also happen with the as_json method
  ShillerDataMonth Load (3.3ms)  SELECT "shiller_data_months".* FROM "shiller_data_months" WHERE "shiller_data_months"."year_month" = '2011.12' LIMIT 1
  ShillerDataMonth Load (0.6ms)  SELECT "shiller_data_months".* FROM "shiller_data_months" WHERE "shiller_data_months"."year_month" = '2011.12' LIMIT 1
  ShillerDataMonth Load (0.6ms)  SELECT "shiller_data_months".* FROM "shiller_data_months" WHERE "shiller_data_months"."year_month" = '2011.12' LIMIT 1
  ShillerDataMonth Load (0.5ms)  SELECT "shiller_data_months".* FROM "shiller_data_months" WHERE "shiller_data_months"."year_month" = '2011.12' LIMIT 1
  ShillerDataMonth Load (0.5ms)  SELECT "shiller_data_months".* FROM "shiller_data_months" WHERE "shiller_data_months"."year_month" = '2012.01' LIMIT 1
....

モデルにメソッドを追加してこれを修正しました。

def self.json_formatting(collection)
  result = []
  collection.each do |shiller_data_month|
    result << shiller_data_month.attributes
  end
  result
end

コントローラーでこのメソッドを使用します

def historic_returns
  respond_to do |format|
    format.json do
      start_date = Date.new(params[:start_year].to_i, params[:start_month].to_i)
      end_date = Date.new(params[:end_year].to_i, params[:end_month].to_i)
      @result = ShillerDataMonth.records_between_two_dates(start_date, end_date)
      render :json => ShillerDataMonth.json_formatting(@result)
    end
  end
end

結論として、Rails のデフォルト (Rails のデフォルトが to_json か as_json かは不明) を使用する代わりに、オブジェクトのコレクションをハッシュのコレクションに変換する独自のメソッドを作成することで、複数のクエリの問題を修正しました。

于 2013-07-09T21:25:59.823 に答える
0

N+1 の問題があるようです。詳細についてはこちらをご覧ください - http://guides.rubyonrails.org/active_record_querying.html#eager-loading-associations

于 2013-07-09T02:40:31.613 に答える