データベースの問題を修正する
データベースは、Web アプリケーションのパフォーマンスの問題の主な原因の 1 つです。データベースは膨大な量のデータを処理する必要があるため、クエリを準備する際の小さなアルゴリズムエラーでさえ、重大な結果につながる可能性があります。これは、ORM システムを使用する場合に特に当てはまります (この章の例ではエンティティフレームワークを使用します)。
DPA は、長いクエリ実行時間、多数のデータベース接続、多数の同じデータベースコマンド、応答内の多数のレコードに関連するデータベースの問題を検出します。問題は、動的プログラム分析ウィンドウのデータベースタブにグループ化されています。

この章では、このような問題につながる可能性のあるコード設計の例と、それを修正する方法に関するヒントを紹介します。
DB コマンド時間
コマンドの実行時間が指定されたしきい値を超えると、DPA はコマンドを実行するコードに DB コマンド時間の問題をマークします。特定のコマンドの実行時間が長い理由を 1 つだけ特定するのは困難です。このような問題は、複雑な結果のクエリ、ネットワーク接続の問題などに関連している可能性があります。長いコマンド時間がまったく問題にならない可能性は十分にあります。これはアプリケーションの動作方法であり、状況を修正するために何もできません。
デフォルトのしきい値は 500 ミリ秒です。
直す方法
問題の背後にはさまざまな理由が考えられるため、次のような唯一のアドバイスがあります。
問題のあるコードを見つけて、動的プログラム分析ウィンドウで対応する問題を開きます。

問題の詳細で、SQL クエリを確認します。

それでも問題の原因が明確でない場合は、データベースサーバーでクエリを直接実行してみて、通信の問題、キャッシュサイズの制限、インデックスが作成されていない列、テーブルロック、デッドロックなど、考えられるすべての原因を 1 つずつ除外してください。
DB 接続
データベースへの同時接続数がしきい値を超えると、DPA は接続を開くコードに DB 接続問題のマークを付けます。例: 実行中、関数は 100 接続、次に 200 接続、次に 150 接続を開閉します。しきい値が 50 接続に設定されていると仮定すると、結果の問題値は「200 接続」になります。
デフォルトのしきい値は 10 接続です。
以下に、接続リークの考えられる理由のいくつかを示します。
「try」ブロックでの接続リーク
次のコードを考えてみましょう:
コマンドの実行後に接続を閉じますが、コマンドが例外をスローした場合、接続は開いたままになります。さらに悪いことに、接続が開いていることさえ知らずに例外を処理してしまいます。

直す方法
いずれの場合も、finally ブロックを使用して接続を閉じる必要があります。
SQLDataReader による接続リーク
データベースから行のストリームを読み取るために SQLDataReader を使用する場合は、正しい CommandBehavior を使用していることを確認してください。例を考えてみましょう:
SqlDataReader インスタンスは、コマンドの実行後に接続を閉じません。リーダーが何度も作成されると、対応する数の開いている接続が生成されます。

直す方法
CommandBehavior.CloseConnection 経由で接続を閉じる SqlDataReader のインスタンスを使用していることを確認してください。ここでの問題は、デフォルトまたは別の動作の SqlDataReader が他のコードで必要になる可能性があることです。この場合、コードをリファクタリングして、必要なすべてのユースケースの動作を備えた SqlDataReader のインスタンスを作成する必要があります。
DB コマンド
コマンド実行回数がしきい値を超えると、DPA は同じコマンドを複数回実行するコードを DB コマンド問題としてマークします。デフォルトのしきい値は 50 コマンドです。
このチェックが存在する主な理由は、よく知られている N+1 問題を防ぐためです。例: ブログのテーブルがあり、各 Blog には多数の投稿があります。Blog から Post は 1 対多の関係です。すべてのブログのすべての投稿のリストを取得するとします。エンティティフレームワークでこれを行う簡単な方法は次のとおりです。
上記のコードでは、N+1 クエリが生成されます。ここで、N は投稿の総数です (すべてのブログを選択し、各ブログから投稿を選択します)。

直す方法
データベースへの 1 回の要求で必要なすべてのデータを取得してみてください。例:
DB レコード
データベースコマンドがしきい値を超えるレコード数を返す場合、DPA はコマンドを実行するコードに DB 接続の問題としてマークします。場合によっては、多数のレコードを取得することが設計上暗黙的に行われます。ただし、最適でないコードパターンが原因で、これが偶然に発生することもあります。
デフォルトのしきい値は 100 レコードです。
IQueryable を IEnumerable にキャストする
IQueryable は外部データソースへのクエリを意味しますが、IEnumerable はインメモリデータのみをクエリします。IEnumerable コレクションに対してクエリを実行すると、アプリケーションはまずデータベースからすべての関連データを取得し、次にメモリ内データにクエリを適用します。IQueryable を使用すると、アプリケーションはクエリを外部データベースに直接送信します。次の例を考えてみましょう。
上記の例で取得したいのは、何らかの条件に一致する投稿の数だけです。理論的には、これは SELECT COUNT データベースクエリで実行できます。実際には、CustomFilter は IEnumerable コレクションのみを受け入れるため、クエリは IQueryable から IEnumerable にキャストされます。その結果、行 CustomFilter(dbContext.Posts.Where(_ => _.PostId > 0)).Count() はすべての投稿を次のようにメモリにロードします。
次に、メモリ内の投稿のコレクションにフィルターが適用されます。DPA の問題は、このクエリが原因で受け取ったレコードの数を示しています。

示されている例は非常に明白です。実際のアプリケーションでは、このようなキャストは多数の呼び出し内に隠されている場合があります (たとえば、クエリフィルターチェーン内)。
直す方法
フィルター関数は明示的に IQueryable コレクションを使用する必要があります。例:
CustomFilter は IQueryable と連動するようになったため、CustomFilter(dbContext.Posts.Where(_ => _.PostId > 0)).Count() クエリは次のように変換されます。
すべてのフィルタリングはサーバー側で行われ、アプリケーションはカウント結果を含む 1 つのレコードのみを受け取ります。
関連ページ:
DPA スコープを絞り込む
特定の問題を DPA 問題リストから除外したい場合が数多くあります。主なものは次のとおりです。これは問題ではありませんすべてが意図したとおりに動作するにもかかわらず、DPA が特定のメソッドを問題としてマークする場合があります。例: メソッドが大量のメモリを割り当てる場合があります。これはコード設計が間違っているためではなく、単に現在のユースケースで必要なためです。これらがほんの数個の方法である場合、最善の解決策は、これらの問題を抑制することです。誤検知が多数発生する場合は、おそらく問題のしきい...
メモリの問題を修正
プログラムにメモリ割り当てが不可欠な場合、DPA がそれを問題のメトリクスとして使用するのはなぜですか? 問題は、パフォーマンスの点で非常に安価なメモリ割り当てではなく、多くのシステムリソースを必要とする可能性のあるガベージコレクション(GC)にあります。より多くのメモリを割り当てるほど、将来的に収集する必要があります。.NET がメモリを管理する方法についての簡単なリマインダーについては、JetBrains dotMemory ドキュメントを参照してください。DPA は、クロージャ、スモールオ...