Ruby
 Computer >> コンピューター >  >> プログラミング >> Ruby

Ruby on Rails データベースのパフォーマンスをマスターする:テストと最適化戦略

この記事では、Rails でデータベースのパフォーマンスをテストする方法と、最も一般的なデータベースのパフォーマンスの問題のいくつかを解決する方法を学びます。

Rails アプリケーションを開発する場合、ActiveRecord はデータベースを管理するデフォルトのツールです。 ActiveRecord は、.where などのコマンドを使用してデータをクエリおよび挿入するための簡単かつ高速なインターフェイスを提供します。 、.save.create.update 。 Rails はこれらのコマンドを SQL クエリに変換する作業を行います。これは良いことですが、場合によってはパフォーマンスの問題を引き起こす可能性があります。一般的な問題のいくつかとパフォーマンスを最適化する方法を理解することが重要です。

Ruby on Rails の ActiveRecord に関する簡単なメモ

Rails ActiveRecord は、データベースをビジネス オブジェクトとして表すことでデータベースを管理する Model-View-Controller (MVC) のレイヤーです。 ActiveRecord パターンは、ORM 技術を使用して、アプリケーションのオブジェクトをリレーショナル データベース テーブル管理システムに接続します。

さあ、始めましょう!

Rails でデータベースのパフォーマンスの問題を特定してテストする 3 つの方法

1. ActiveRecord クエリで Explain を実行する

Explain ステートメントには、SQL クエリの実行計画に関する情報が表示されます。これには、スキャンされる行数、使用されるインデックス、テーブルの結合方法など、クエリがどのように実行されるかが含まれます。

実行プランは、以下を確認することで、クエリの実行を遅らせている原因を特定するのに役立ちます。

  • クエリのパフォーマンスを向上させるために追加する必要があるインデックス
  • テーブルが最適な順序で結合されているかどうか。 STRAIGHT_JOIN を使用できます。 パフォーマンスを向上させるために、結合ステートメントでテーブルの順序を強制します。

Explain は、SELECT、DELETE、INSERT、REPLACE、UPDATE ステートメントでも機能します。

ActiveRecord で Explain を使用するのは非常に簡単です。次のように入力します。

 

.explain を追加しています コマンドの最後に、ActiveRecord コマンドのクエリ プランが表示されます。上記の例は、id を使用する非常に単純なクエリです。 (主キー) を使用してテーブルをクエリします。 explain の出力 ステートメントは、pkey を使用していることを示しています。 。このことから、ステートメントが最適かつ高速であることがわかります。

.explain を追加してみてください。 コマンドを遅いクエリに実行して、使用されたインデックスとともに実行順序を明らかにします。クエリ プランに Seq Scan が表示されている場合 、インデックスは使用されていないため、クエリを変更するか、新しいインデックスを追加する必要があります。

結合を使用した別の例を次に示します。

 

ここでは、user テーブルが Collaborations テーブルと結合されます。クエリ プランを調べると、コラボレーション テーブルは seq scan を使用しています。 が最初に実行されますが、ユーザー テーブルは pkey を使用しています。 インデックスが作成され、後で実行されます。 user_id にインデックスを追加できます。 このクエリを最適化するには、コラボレーション テーブルの列を使用します。 Explain はクエリを細分化するのに役立つため、最適化が必要な場所を把握できます。

2.主要なデータベース指標を測定する

クエリのパフォーマンスを確認するために測定する指標はクエリ時間だけではありません。次のような他のデータベース 指標も見てください。

<オル>
  • CPU 使用率
  • メモリ使用量
  • 待機中の IO 用のディスク キュー
  • 受信トラフィックと送信トラフィックのネットワーク帯域幅
  • 利用可能なディスク容量
  • スループット
  • これらのメトリクスが特定のしきい値を超えると、クエリの速度が低下する可能性があります。パフォーマンスの問題を理解するには、時間範囲全体でデータ ポイントを確認する必要があります。

    測定する必要があるデータ ポイントは、次のような多くの要因によって決まります。

    • データベースの種類:

      • リレーショナル
      • メモリ内
      • SQL を使用しない
      • データ ウェアハウス
    • サーバーのホスト方法:

      • オンプレミス
      • クラウド上

    データベースの指標を監視する唯一の方法はありません。さまざまな要因によって異なります。

    3. AppSignal を使用して Rails アプリのパフォーマンスを測定する

    すべてのクエリを可視化できる中央の場所がなければ、すべてのパフォーマンス メトリクスを管理することが困難になる可能性があります。すべてのコード ブロックにパフォーマンス コードを追加すると、煩雑で管理不能になる可能性があります。

    AppSignal などのツールを使用すると、パフォーマンス測定をアプリケーションに簡単に統合できます。 AppSignal は、すぐに使える Rails をサポートします。 AppSignal の簡単なインストール プロセスについては、「AppSignal for Ruby」ドキュメントを参照してください。

    注目すべき重要な指標には次のようなものがあります。

    • クエリが遅い
    • スループットに基づくデータベースのパフォーマンス
    • N+1 クエリ
    • データベースのレイテンシ
    • アクティブな接続の数

    AppSignal ダッシュボードは次のようになります。

    Ruby on Rails データベースのパフォーマンスをマスターする:テストと最適化戦略

    Ruby on Rails データベースのパフォーマンスを最適化する 7 つの方法

    1. N+1 クエリの積極的な読み込み

    N+1 クエリは、データベースのパフォーマンスに関する最も一般的な問題です。 N+1 の例を見てみましょう。 ユーザーとプロジェクトという 2 つのモデルがある場合のクエリ:

     

    ここで、ユーザー名とプロジェクト名を検索したい場合は、次のコードを実行します。

     

    上記のコードはループごとにデータベースにクエリを実行し、パフォーマンスの問題を引き起こします。実行されるクエリの合計数は、ユーザー数 + 1 になります。

    この問題を解決するのは非常に簡単です。関連付けを積極的にロードするだけです。 .includes(:projects) を追加するだけです クエリの最後:

     

    上記のクエリはプロジェクトを積極的にロードするため、ループを実行してもデータベースはクエリされません。

     

    Rails 6.1 は厳密なロードを提供し、アソシエーションがアクセスされる前に確実にロードされるようにします。厳密なロードを有効にするには、モデルに次の行を追加します。

     

    ここで、積極的にロードせずにプロジェクトにアクセスしようとすると、Rails は ActiveRecord::StrictLoadingViolationError をスローします。 例外。

    Rails 6.1 をお持ちでない場合は、Bullet などの gem を使用できます。

    2.データベースインデックスを使用する

    データベースは、データをより速く取得できるようにインデックスを提供します。前に説明した Explain コマンドを使用すると、クエリが適切なインデックスを使用しているかどうかを確認できます。

    遅いクエリを変更して、既存のインデックスを使用するか、パフォーマンスの向上に役立つ追加のインデックスを使用することができます。

    MySQL には 4 つの異なるタイプのインデックスがあります。

    <オル>
  • 主キー - インデックスは主キーに自動的に追加され、一意であることも保証されます
  • 一意 - 一意のキー インデックスにより、属性に追加された項目が常に一意であることが保証されます
  • インデックス - 主キー以外の属性に追加
  • 全文 - 文字ベースのデータに対するクエリに役立ちます
  • インデックスは B ツリーまたはハッシュ形式で保存されます。

    インデックスは、単一のフィールドに追加することも、複数のフィールドの組み合わせとして作成することもできます。複合インデックスは、複数のフィールドを含むクエリを最適化するのに役立ちます。インデックスを 1 つだけ使用する場合は、大規模なデータセットのスキャンが必要になります。

    たとえば、次のクエリには 2 つのフィールドがあります。

     

    プロジェクト "abc" には多数のユーザーが存在する可能性があります 国フィールドがスキャンされます。結果データセットが大きいため、これは処理が遅くなる可能性があります。この場合、プロジェクト フィールドと国のフィールドの両方に複合インデックスを追加して、パフォーマンスを向上させることができます。

    次の ActiveRecord 移行コマンドを使用して、Rails にインデックスを追加できます。

    単一インデックス:

     

    複合インデックス:

     

    3.使用制限

    返されるレコードが増えるほど、パフォーマンスが低下する可能性があります。大きなデータセットを返す単一のクエリよりも、複数のクエリを実行する方が効果的です。

     

    次の 100 バッチをフェッチするには、オフセットを使用できます。

     

    これにより、パフォーマンスが大幅に向上します。留意すべき点の 1 つは、オフセットが大きくなると、クエリが遅くなるということです。オフセットに制限を追加します。

    4. find_each を使用してください 多数の項目をロードするには

    レコードを反復処理するときは、パフォーマンスを向上させるために Rails でバッチ処理します。

     

    これにより、データベース内のすべてのレコードが 1 回クエリされるため、メモリとデータベースのパフォーマンスの問題が発生します。

    find_each を使用する または find_in_batches 同じ操作をバッチで実行すると、パフォーマンスが向上します。

     

    デフォルトでは、find_each クエリの結果はバッチ 1,000 になります。バッチ サイズを変更するには、引数として定義します。

     

    find_in_batches を使用することもできます 実行する必要がある操作に基づいて。 find_in_batches の違い および find_each find_in_batches ですか 結果は個々のレコードではなくモデルの配列として生成されます。

    5. Pluck を使用して必須フィールドを選択してください

    Pluck コマンドは、クエリの結果を ActiveRecord オブジェクトではなく配列に直接変換します。

    クエリが大きな結果を返す場合、Pluck を使用するとコードのパフォーマンスが向上します。 Pluck はデータベースから必須フィールドのみを選択します。

     

    結果はメイン テーブルではなくインデックスからフェッチされ、並べ替えを伴うクエリでより効果的です。

    6.一括操作を使用する

    一括削除 ActiveRecord オブジェクトをループする削除操作は、レコードを一度に 1 つずつ削除します。

     

    各レコードを削除するには、データベースに対して多くのクエリを実行する必要があります。代わりに、単一の一括 delete_all を使用するのが最適です。 クエリ:

     

    一括作成 一括削除と同様に、ActiveRecord を使用して一括挿入も実行できることを知らない人もいます。これにより、n を削減できます。 クエリの数は 1 つだけです。 ActiveRecord::Base create メソッドはハッシュの配列を入力として受け入れます:

     

    7.必要に応じてインメモリ計算を使用する

    場合によっては、クエリよりもメモリ内計算の方が望ましい場合があります。ユーザーの記録がない国をデータベース内で検索するとします。

     

    上記のクエリでは、結果を取得するために N 回のクエリが必要でした。この代わりに、指定された国のユーザーを検索する単一のクエリを作成し、メモリ内で他の計算を行うことができます。

     

    キャッシュを使用してリクエストとレスポンスのサイクルを再利用し、場合によってはデータベースの負荷を軽減することができます。 Rails は、ページ、アクション、およびフラグメント キャッシュの 3 種類のキャッシュ手法を提供します (フラグメント キャッシュはデフォルトで提供されます)。

    まとめ:ActiveRecord と AppSignal を使用して Ruby on Rails のパフォーマンスを最適化する

    さて、要約する時間です!この投稿では、Rails でデータベースのパフォーマンスの問題を特定してテストする 3 つの方法について説明しました。

    • ActiveRecord クエリでの Explain の実行
    • 主要なデータベース指標の測定
    • AppSignal を使用した Rails アプリのパフォーマンスの測定

    また、データベースのパフォーマンスを最適化する 7 つの方法には、次のようなものがあります。

    • N+1 クエリの積極的な読み込み
    • データベースインデックス
    • 制限
    • find_each 多数の項目をロードする
    • 必須フィールドを選択してください
    • 一括操作
    • メモリ内計算

    Rails を使用すると、アプリケーションを非常に簡単かつ迅速に開発できます。 ActiveRecord は、データベース コードの生産性、再利用性、保守性の向上に役立ちます。 ActiveRecord クエリがどのように SQL クエリに変換され、実行されるかを理解することが重要です。

    ただし、Rails データベースのパフォーマンスを最適化するために必要な最も重要なことは、パフォーマンス データの可視性です。パフォーマンスの問題はよくあることですが、この問題を可視化すれば解決できます。データベース メトリックを提供する適切な監視ツールが必要です。私たちは AppSignal が好きです;)

    追記Ruby Magic の投稿を報道後すぐに読みたい場合は、Ruby Magic ニュースレターを購読して、投稿を 1 つも見逃さないようにしてください。


    1. Rails でのロギングをマスターする:デバッグからプロアクティブなアラートまで

      ほとんどの人は、ログが最も必要なときにのみログの必要性を認識します。しかし、アプリケーションが壊れ、ユーザーからの苦情が殺到し始め、それを修正する方法が見当もつかないとき、役立つかもしれないログ メッセージを追加しても手遅れです。 良い丸太は 10 倍の価値があります。これらを使用すると、これらの厄介なバグの診断が簡単になり、ログを正しく作成すれば、ユーザーが気づく前に問題を警告することができます。しかし、「ロギングを正しく行う」とはどういう意味でしょうか? ロギングは始めるのは簡単ですが、マスターするのは困難です。この投稿では、Rails アプリケーションのログを最大限に活用する方法につ

    2. RubyでStructとOpenStructを使用する方法

      Rubyの構造体とは何ですか? 構造体は組み込みのRubyクラスであり、値オブジェクトを生成する新しいクラスを作成するために使用されます。値オブジェクトは、関連する属性を一緒に格納するために使用されます。 ここに例があります : Point 2つの座標(x &y 。 このデータはさまざまな方法で表すことができます。 いいね : 配列[10, 20] ハッシュ{ x: 10, y: 10 } オブジェクトPoint.new(10, 20) 複数のPointを使用する場合 、オブジェクトアプローチを使用することをお勧めします。 しかし… これら2つの値を一緒に格納するた