SQL 데이터에 ienumerable 반환 유형을 사용하는 데 대한 함정이 있습니까?

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 객체의 반복 사이에 긴 실행 시간이 긴 유사한 코드를 실행하는 많은 프로세스가있는 경우 문제가 될 수 있습니다. 그러나 CPU 사용을 줄일 수 있다는 것은 그럴듯 해 보입니다. SQL Server에서 ienumerable 객체를 사용하는 경우에만 데이터를 반환하기 때문입니다. 또한 클라이언트가 MyType의 모든 발생을로드하지 않고 작동하는 동안 MyType의 한 인스턴스 만로드해야하므로 클라이언트의 메모리 사용량을 낮추는 경우 (전체 데이터 레이더를 반복하고 목록이나 무언가를 반환 함).

  • 이런 식으로 ienumerable을 사용하고 싶지 않은 곳에 대해 생각할 수있는 사례가 있습니까? 아니면 완벽하게 적합하다고 생각하는 경우가 있습니까?

  • SQL 서버에 어떤 종류의 부하가 있습니까?

  • 이것이 당신이 당신의 자신의 코드에서 사용할 것인가 (nhibernate, subsonic 등에 대한 언급)입니까?

  • -
도움이 되었습니까?

해결책

나는 그것을 사용하지 않을 것이며, 그것이 일어나고있는 일을 숨기고 적절한 처분없이 데이터베이스 연결을 남길 수 있기 때문입니다.

마지막 레코드를지나 읽은 경우 연결 객체가 닫히고, 이전에 읽기를 중지하면 연결 객체가 배치되지 않습니다. 예를 들어, 당신이 결과에 항상 10 개의 레코드가 있고 마지막 항목을 넘어 읽는 열한 번째 읽기 호출을하지 않고 열거 자의 10 개의 레코드를 읽는 루프가 있다는 것을 알고 있다면 연결은 제대로 닫히지 않습니다. 또한 결과의 일부만 사용하려면 나머지 레코드를 읽지 않고 연결을 닫을 방법이 없습니다.

열거자를위한 내장 확장도조차도 Seamlingy를 올바르게 사용하더라도이를 유발할 수 있습니다.

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