7

家具工場の生産フローを監視する Web アプリケーションを作成しています。処理するデータは数千あります。これまでのところ、Mongrel + MySQL で RoR を実行していますが、非常に遅いです (一部のビューでは 2 ~ 4 分)。RoR ログを見ると、データベース クエリは遅くないようです (0 ~ 10 ミリ秒)。

データベース データをオブジェクトに変換するとき、RoR は遅くなりますか? 雑種は遅いですか?

編集:最初に:私は開発者でした。環境 実稼働環境では、最も遅いビューで 2 分かかります (これは、良好なコンピューターでは 1 分未満に短縮されます。私のコンピューターは 5 年使用されています)。ruby-prof と少しの常識で、どのメソッドがアプリケーションの速度を低下させているかを突き止めました。問題は、単一の SQL クエリが大規模なデータセットのループで呼び出されることです。

ofs = Ofkb.find_by_sql ["..some large SQL query..."]

for of in ofs # About 700-1000 elements
   ops = Operation.find(..the single query..)
   etc.
end

これらのメソッドでの ruby​​-prof の結果は次のとおりです。

 %self     total     self     wait    child    calls  name
 32.19     97.91    97.91     0.00     0.00       55  IO#gets (ruby_runtime:0}
 28.31     86.39    86.08     0.00     0.32    32128  Mysql#query (ruby_runtime:0}
  6.14     18.66    18.66     0.00     0.00    12432  IO#write (ruby_runtime:0}
  0.80      2.53     2.42     0.00     0.11    32122  Mysql::Result#each_hash (ruby_runtime:0}

問題は、これらの単一のクエリを実際に回避できないことです。複雑なデータを計算する必要がある何千ものイベントがあります。現在、ページを最初にリクエストしない限り、これらのメソッドで memcached を使用しています。

4

11 に答える 11

5

ビュー アクセスごとに実行される 0 ~ 10 ミリ秒のクエリの数は? データ モデルのどの部分が参照されていますか? :include を使用して、アソシエーションを積極的にロードしていますか?

Rails は、あなたが作るのと同じくらい遅いです。理解するとスピードがついてきます (通常!)

上記を拡張すると、特に、ビューが なしで「多」側を参照している has_many 関連付けがあります:includeか? これによりfind(:all)、マスター テーブルで詳細への結合が実行されます。多数の詳細レコードがあり、それらすべてを個別に処理している場合、コストが高くなる可能性があります。

このようなもの:

Master.find(:all, :include => :details)

...役立つかもしれません。ただし、まばらな情報から推測します。

このテーマに関する古い Railscast があります。

于 2009-02-19T18:01:48.927 に答える
5

RnRは遅いという評判がありますが、これは言語の単純な問題とするには極端すぎるように思えます。

プロファイラーを実行して、遅い関数とその理由を正確に判断する必要があります。Web アプリケーションの速度を低下させる最も一般的な原因は、「n+1 問題」です。つまり、データベースに n 個のデータ項目がある場合、アプリはそれらを取得する 1 つのクエリを作成するのではなく、データベースに対して n 個の個別のクエリを作成します。しかし、プロファイラーを実行するまではわかりません。ruby-profは、私が使用したプロファイラーの 1 つです。

プロファイル結果の編集に基づいて編集:

クエリ ループはいつでも削除できると固く信じています。Mike Woodhouse が言うように、これを行う Rails の方法は、 has_manyまたはその他の関連付けを使用してテーブル間の関係を指定し、Rails に自動的にテーブル結合を生成させることです。これは明確で高速で、「Rails の方法」です。ただし、生の SQL を使用して開始する場合、またはこの場合に関連付けが機能しない場合は、適切な結合を自分で生成するだけで済みます。他のすべてが失敗した場合は、ループを通じて以前に見つかった結果を保持するビューまたは非正規化されたテーブルを作成できます。実際、生成されたクエリを反復処理する必要があるという事実は、テーブルの設計自体にいくつかの欠陥があることを示している可能性があります。

とはいえ、クエリ結果のキャッシュが十分に機能する場合は、そのままにしてください。必要に応じて最適化します。

于 2009-02-19T18:08:48.787 に答える
4

これは正常ではありません。あなたはあなたを遅くしているいくつかのロジックを持っています. 時間がかかっていると思われるコードの一部をコメントアウトしてみて、それが役立つかどうかを確認してください。そうであれば、そのロジックを最適化する方法を理解する必要があります。

非常に多数のオブジェクトを反復するループで多くの計算を行っている場合、もちろん遅くなります。

この種の問題は、どの言語やフレームワークでも発生する可能性があります。Ruby は他の言語ほど高速ではありませんが、ほとんどの場合十分に高速です。大規模なデータセットを常に計算する必要がある場合、Ruby は適切な言語ではない可能性があります。パフォーマンスを消耗するコードを処理する Ruby C 拡張機能を作成することを検討してください。ただし、最初に診断とリファクタリングを試みてください。

最後に、 RubyProfをチェックして、ボトルネックを見つけるのに役立つかどうかを確認してください。

于 2009-02-19T17:56:59.117 に答える
3

前の 2 つの回答は、特にパフォーマンス監視ツールを使用する場合に役立ちます。私はNew Relic RPMを使用しており、過去に非常に役に立ちました。

ただし、これらの種類のツールは、たとえば 3 秒から 1 秒未満にスピードアップしようとしている場合に最適です。

ビューのレンダリングに 2 ~ 4 分かかることは、通常の状況では絶対に正常ではありません。

ボトルネックがどこにあるかを把握するために、開発ログをいくつか見せていただけますか?

ブラウザーが画像、JavaScript、またはその他のファイルを読み込むのにかかる時間をこの合計測定値に含めていますか?

于 2009-02-19T18:07:15.073 に答える
0

JRuby を使用するか、Ruby 1.9 に切り替えることができます。
どちらもパフォーマンスが大幅に向上するはずです。
JRuby の問題は、C を使用する gem がコンパイル/動作しないことです。jruby の「gem」アプリによってインストールされる Java に相当するものがありますが、いくつかの gem は単純に機能しません。

基本的に Ruby 1.9 でも同じ問題が発生します。構文が少し変更されましたが、主な問題は、大量の gem が機能しなくなったことです。ただし、人々は更新の進行中です(http://isitruby19.com/で進行状況を確認してください)

于 2009-02-19T20:18:53.600 に答える
0

何かを行う前に最初にコードをプロファイリングするかもしれませんが、 for ループ内のクエリはパフォーマンスの問題の非常に一般的な原因であり、一見するとこれが問題のように見えます。とにかく実用的なプロファイラーをここで見つけることができます:

他の回答で既に述べたように、両方のモデルが関連している場合は、関連付けを積極的にロードする必要があります。これは、結合クエリを実行するよう Active Record に指示することを意味します。

#left outer join
ofkbs=Ofkb.includes(:operation).where(name: "banana")

ofkbs が不要で操作のみが必要な場合は、内部結合を実行できます。

#inner join (discards the Ofkbs that do not have any operation)
operations=Operation.joins(:ofkb).where(ofkb:{name:"banana"})

このソリューションでは、1 つのクエリのみを実行し、DB から既に収集されているデータを後で反復処理できます。

operations=ofkbs.map{|of| of.operations}.flatten

operations.each do |o|
  do_whatever_you_want_with_operation(o)
end

クエリが非常に複雑な場合は、代わりにarelを使用する必要があります。

于 2014-07-23T10:33:45.370 に答える
0

このトピックに関するいくつかの優れたスクリーン キャストがありますhttp://railslab.newrelic.com/scaling-rails

Fragmet キャッシングや :include の使用 (n+1 を回避するため) などが役に立ちます。すでに memcached を使用しているようですね。では、url を curl してキャッシュをプリフェッチしてみませんか?

于 2009-02-25T11:19:15.640 に答える
0

サーバーを0.0.0.0ではなくボックスのIPアドレスにバインドすると、速度が向上しました。

于 2010-11-11T17:52:59.337 に答える
0

毎回データベースにクエリを実行するのではなく、すべてのデータをプリフェッチし、for ループでメモリ内のローカルに検索してみませんか? 1 つのビューに対する数千のクエリは、設計に深刻な問題があることを示しています。

于 2009-02-20T20:18:48.177 に答える
0

実行時間がこれほど長くなると、ネットワークの問題が疑われます。プライマリ DNS サーバーで DNS クエリがタイムアウトしている可能性があります。

于 2009-02-19T18:13:06.257 に答える