2013-03-13 25 views
15

Oto mój przykładowy kod, który używam do pobierania danych z bazy danych: na warstwie DAO:Zastanawiam o stanie połączenia i wpływie na wydajność kodu przez „plon” podczas iteracji po danych czytnika obiektu

public IEnumerable<IDataRecord> GetDATA(ICommonSearchCriteriaDto commonSearchCriteriaDto) 
{ 
    using(DbContext) 
    { 
     DbDataReader reader = DbContext.GetReader("ABC_PACKAGE.GET_DATA", oracleParams.ToArray(), CommandType.StoredProcedure); 
     while (reader.Read()) 
     { 
      yield return reader; 
     } 
    } 
} 

na warstwie BO Wołam powyższej metody jak:

List<IGridDataDto> GridDataDtos = MapMultiple(_costDriversGraphDao.GetGraphData(commonSearchCriteriaDto)).ToList(); 

na odwzorowujący metodą warstwa MapMultiple jest zdefiniowany następująco:

public IGridDataDto MapSingle(IDataRecord dataRecord) 
{ 
    return new GridDataDto 
    { 
     Code = Convert.ToString(dataRecord["Code"]), 
     Name = Convert.ToString(dataRecord["Name"]), 
     Type = Convert.ToString(dataRecord["Type"])  
    }; 
} 
public IEnumerable<IGridDataDto> MapMultiple(IEnumerable<IDataRecord> dataRecords) 
{ 
    return dataRecords.Select(MapSingle); 
} 

Powyższy kod działa dobrze i dobrze, ale zastanawiam się nad dwoma problemami z powyższym kodem.

  1. Jak długo będzie otwarte połączenie czytnika danych?
  2. Kiedy rozważam tylko współczynnik wydajności kodu, czy dobrym pomysłem jest użycie "zwrotu plonów" zamiast dodawania rekordu do listy i zwracania całej listy?

Odpowiedz

12
  1. Twój kod nie pokazuje, gdzie otwierasz/zamykasz połączenie; ale czytnik tutaj będzie faktycznie otwarty tylko podczas iteracji danych. Odroczone wykonanie itp. Jedynym bitem twojego kodu, który to robi jest .ToList(), więc będzie dobrze. W bardziej ogólnym przypadku tak: czytelnik będzie otwarty na czas, który wykonasz, aby go powtórzyć; jeśli zrobisz .ToList(), który będzie minimalny; jeśli zrobisz foreach i (dla każdego przedmiotu) zrób zewnętrzne żądanie http i poczekaj 20 sekund, a następnie tak - będzie dłużej otwarte.
  2. Oba mają swoje zastosowania; nie buforowane podejście jest świetne dla wielkich wyników, które chcesz przetworzyć jako strumień, bez konieczności ładowania ich do pojedynczej listy w pamięci (lub nawet mieć wszystkie w pamięci na raz); Zwracanie listy powoduje szybkie zamknięcie połączenia i ułatwia uniknięcie przypadkowego użycia połączenia, gdy ma już otwarty czytnik, ale nie jest idealne dla dużych wyników.

Po zwrocie bloku iteratora dzwoniący może zdecyduj, co jest zdrowe; jeśli zawsze zwrócisz listę, nie mają zbyt wiele opcji. Trzecim sposobem (który robimy w eleganckim) jest dokonanie wyboru ich; mamy opcjonalny parametr bool, który domyślnie "zwraca listę", ale który wywołujący może się zmienić, aby wskazać "return iterator block"; zasadzie:

bool buffered = true 

w parametrach, oraz:

var data = QueryInternal<T>(...blah...); 
return buffered ? data.ToList() : data; 

w realizacji. W większości przypadków zwracanie listy jest całkowicie uzasadnione i pozwala uniknąć wielu problemów, dlatego domyślnie to robimy.

+0

dzięki za szybką odpowiedź i pomoc! –

3

Jak długo będzie otwierane połączenie czytnika danych?

Połączenie pozostanie otwarte, dopóki nie zostanie usunięte reader, co oznacza, że ​​będzie otwarte aż do zakończenia iteracji.

Kiedy współczynnik wydajności kodu Uważam tylko, Czy to dobry pomysł, aby użyć yield return zamiast dodanie rekordu do listy i powrocie całą listę?

To zależy od kilku czynników:

  • Jeśli nie planuje się pobrać całą wynik, yield return pomoże Ci zaoszczędzić na ilości przesyłanych danych w sieci
  • Jeżeli nie jesteś planowanie konwertowania zwracanych danych do obiektów lub jeśli do utworzenia pojedynczego obiektu jest używanych wiele wierszy, yield return pomoże zaoszczędzić na pamięci używanej w szczycie punktu użytkowania programu
  • Jeśli planujesz iterować zbiór wyników enture tak jak Po upływie określonego czasu nie będzie kar umownych za korzystanie z usługi yield return. Jeśli iteracja będzie trwać przez znaczny czas na wielu równoczesnych wątkach, liczba otwartych kursorów po stronie RDBMS może zostać przekroczona.
0

Ta odpowiedź ignoruje błędy w przedstawionej implementacji i obejmuje ogólną ideę.

Jest to kompromis - nie można stwierdzić, czy jest to dobry pomysł, nie znając ograniczeń systemu - jaka jest ilość danych, które można uzyskać, zużycie pamięci, które można zaakceptować, oczekiwany ładunek w bazie danych itp.