IEnumerable< T>を使用する場合の落とし穴はありますかSQLデータの戻り値の型?

StackOverflow https://stackoverflow.com/questions/1400146

  •  05-07-2019
  •  | 
  •  

質問

私の質問は、次のコードに基づいたSQL接続ステータス、ロードなどに関するものです。

public IEnumberable<MyType> GetMyTypeObjects()
{
  string cmdTxt = "select * from MyObjectTable";

  using(SqlConnection conn = new SqlConnection(connString))
  {
    using(SqlCommand cmd = new SqlCommand(cmdTxt, conn))
    {
      conn.Open();
      using(SqlDataReader reader = cmd.ExecuteReader())
      {
         while(reader.Read())
         {
            yield return Mapper.MapTo<MyType>(reader);
         }
       }
    }
  }
  yield break;
}

接続がより長く開かれるなどの理由で、IEnumerableオブジェクトの反復間の実行時間が長い同様のコードを実行する多くのプロセスがある場合、これは問題である可能性があります。しかし、これが減少することはもっともらしいIEnumerableオブジェクトが使用されている場合にのみデータを返すため、SQLサーバーのCPU使用率。また、クライアントは動作中にMyTypeのすべての出現をロードするのではなく、MyTypeの1つのインスタンスをロードするだけなので(クライアントはDataReader全体を反復処理してListまたは何かを返すことにより)、クライアントのメモリ使用量を削減します。

  • この方法でIEnumerableを使用したくないと思われるインスタンス、または完全に適合すると思われるインスタンスはありますか?

  • これによりSQLサーバーにどのような負荷がかかりますか?

  • これはあなた自身のコードで使用するものですか(NHibernate、Subsonicなどの言及がない限り)?

  •  -
役に立ちましたか?

解決

これは使用しません。何が起きているのかを隠すためであり、適切な処理を行わずにデータベース接続を残す可能性があるためです。

接続オブジェクトは、最後のレコードを過ぎて読み取ったときに閉じられ、その前に読み取りを停止すると、接続オブジェクトは破棄されません。たとえば、結果に常に10個のレコードがあり、最後のアイテムを超えて読み取る11回目の読み取り呼び出しを行わずに列挙子からこれらの10個のレコードを読み取るループがある場合、接続は正しく閉じられません。また、結果の一部のみを使用する場合、残りのレコードを読み取らずに接続を閉じる方法はありません。

列挙子の組み込み拡張機能でさえ、semlingyで正しく使用した場合でも、これが発生する可能性があります。

foreach (MyType item in GetMyTypeObjects().Take(10)) {
   ...
}

他のヒント

これは私が従うパターンではありません。サーバーの負荷については、ロックについて心配するほど心配しません。このパターンに従うことで、データ取得プロセスがビジネスロジックフローに統合されます。これは、トラブルに対する万能のレシピのようです。イテレーション側で何が起こるかわからず、自分自身を挿入することになります。一度にデータを取得し、リーダーを閉じた後、クライアントコードがデータを列挙できるようにします。

事前に最適化しないことをお勧めします。多くの場合、接続はプールされます。

また、SQL Serverの負荷に違いはありません-クエリは既にコンパイルされており、実行されます。

私の懸念は、あなたが完全にクライアントコードに翻弄されていることです。

呼び出し元のコードは、厳密に必要な時間よりも長く接続を開いたままにする可能性があることを既に述べましたが、オブジェクトを閉じたり破棄したりすることを許可しない可能性もあります。

クライアントコードが foreach using などを使用するか、列挙子の Dispose メソッドを明示的に呼び出す限り、問題ありませんが、このようなことをやめることは何もありません:

var e = GetMyTypeObjects().GetEnumerator();
e.MoveNext();    // open the connection etc

// forget about the enumerator and go away and do something else
// now the reader, command and connection won't be closed/disposed
// until the GC kicks in and calls their finalisers
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top