2017-09-08 11 views
1

を選択し、私はそれは限られたレコードを持つローカル環境で正常に働いている各ソースRailsはグループごとに上位nレコード(メモリリーク)

def latest_results 
    Entry.find_by_sql([" 
    select x.id,x.created_at,x.updated_at,x.source_id,x.`data`,x.`uuid`,x.source_entry_id 
    from 
     (select t.*, 
     (@num:=if(@group = `source_id`, @num +1, if(@group := `source_id`, 1, 1))) row_number 
      from (
     select d.id,d.created_at,d.updated_at,d.source_id,d.`data`,d.`uuid`,d.source_entry_id 
     from `streams` a 
     JOIN `stream_filters` b 
     on b.stream_id=a.id 
     JOIN `filter_results` c 
     on c.filter_id=b.id 
     JOIN `entries` d 
     on d.id=c.entry_id 
     where a.id=? 
     ) t 
     order by `source_id`,created_at desc 
    ) as x 
     where x.row_number <= 10 
     ORDER BY x.created_at DESC 
    ",self.id]) 
    end 

の10件の最新のレコードを返すですfind_by_sqlを使用してこの方法を持っています。 私はアプリケーションにサービスするために2つのGibメモリを持つt2.microを持っています。今私の全体のメモリとアプリを実行しているこのクエリは、frizzing得る。 提案はどうすればよいですか?私はマシンのサイズを増やすことなくこれを解決したい。

答えて

1

私は一度同様の問題がありました。 mysql変数を使用したソリューションは最初はきちんとしているようですが、最適化するのは難しいです。それはあなたのケースで完全なテーブルスキャンを行っているようです。

最初に表示するソースを取得することをお勧めします。次に、ソースごとに1つずつ、上位10の選択肢が複数あり、すべてが共用体と結合された2番目の問合せを実行します。

組合のトップ10には、あなたが簡単にルビーを自動生成することができますいくつかのrepetiveステートメントを持つことになります選択します。

# pseudo code 
sources = Entry.group(:source).limit(n) 
sql = sources.map do |source| 
    "select * from entries where source = #{source} order by created_at limit 10" 
end.join("\nunion all\n") 

Entry.find_by_sql(sql) 
+0

2行目は何をしているのですか?なぜあなたは限界(10)を置くのですか?ソースにはすべてのソースが含まれていなければならず、トップ10入りしているすべてのループバンドルによって、メモリリークが解決されるはずですが、パフォーマンスについてはわかりません。それはどれくらい速いですか? – Mini

+1

私は例として制限10を入れました。なぜなら、あなたは多くの情報源を持っているからです。おそらく、それらをすべて1ページに表示しないでください。問題はmysqlではなく、レンダリングのための柵です。 mysqlは、日付とsoureタイプの適切なインデックスを使用して、数百万のレコードを数秒以内に処理することができます。 –

+0

レコードを大量にレンダリングする必要がある場合は、 raw SQLクエリに 'ActiveRecord :: Base.connection.execute'を追加しました。各エントリごとにアクティブなレコードオブジェクトを作成することはありません。これにより、大量のメモリが節約されます。レポートクエリに5秒かかりますが、100,000を超えるレコードのレンダリングには数分かかる場合もありました。とにかくページングやチャンクの読み込みがより良い戦略です。 –

関連する問題