SqlDataAdapter vs SqlDataReader


131

Jakie są różnice między używaniem SqlDataAdapter a SqlDataReader do pobierania danych z bazy danych?

W szczególności patrzę na ich zalety i wady, a także ich szybkość i wydajność pamięci.

Dzięki

Odpowiedzi:


196

DataReader:

  • Utrzymuje połączenie otwarte aż do zakończenia (nie zapomnij go zamknąć!).
  • Zwykle można powtórzyć tylko raz
  • Nie jest tak przydatny do aktualizacji z powrotem do bazy danych

Z drugiej strony:

  • Ma tylko jeden rekord w pamięci na raz, a nie cały zestaw wyników (może to być OGROMNE )
  • Jest tak szybka, jak tylko możesz w tej jednej iteracji
  • Umożliwia wcześniejsze rozpoczęcie przetwarzania wyników (gdy dostępny jest pierwszy rekord). W przypadku niektórych typów zapytań może to być również bardzo ważne.

DataAdapter / DataSet

  • Pozwala zamknąć połączenie, gdy tylko zakończy się ładowanie danych, a może nawet automatycznie zamknąć je za Ciebie
  • Wszystkie wyniki są dostępne w pamięci
  • Możesz iterować go tyle razy, ile potrzebujesz, a nawet wyszukać określony rekord według indeksu
  • Posiada wbudowane funkcje aktualizacji z powrotem do bazy danych

Kosztem:

  • Dużo większe zużycie pamięci
  • Czekasz, aż wszystkie dane zostaną załadowane, zanim użyjesz któregokolwiek z nich

Tak naprawdę zależy to od tego, co robisz, ale wolę czytnik DataReader, dopóki nie potrzebuję czegoś, co jest obsługiwane tylko przez zestaw danych. SqlDataReader jest idealny dla typowego przypadku dostępu do danych, wiążącego się z siatką tylko do odczytu.

Więcej informacji można znaleźć w oficjalnej dokumentacji firmy Microsoft .


5
DataSet to magazyn danych w pamięci, podczas gdy datareader jest po prostu nośnikiem do pobierania danych. Mówiąc lżej, zapytania Linq można uruchamiać na DataSet, ale nie na serwerze danych.
Partha Choudhury

Właściwie z odrobiną dodatkowego kodu z pewnością można uruchomić zapytania linq (lub przynajmniej jedno zapytanie) na serwerze danych. Po prostu użyj bloku iteratora, aby zwrócić rzutowanie DataReader jako IDataRecord wewnątrz while (reader.Read())pętli.
Joel Coehoorn

7
Ta odpowiedź jest myląca. Jeśli zawiniesz obiekty SqlConnection i SqlDataReader instrukcjami „using” (tak jak i tak powinieneś, ponieważ są one identyfikowalne), połączenie zostanie automatycznie zamknięte. I możesz użyć DataSet z SqlDataReader: po prostu wywołaj DataSet.Load (SqlDataReader).
RickNZ

4
@RickNZ Nie ufaj zbyt szybko, używając instrukcji do zamykania rzeczy. Wywołują metodę Dispose () obiektu, a nie metodę Close (), i natknąłem się na co najmniej jeden przypadek, w którym Dispose faktycznie nie zamknął obiektu za mnie. Zawsze najlepiej jest zawrzeć jawne wywołanie metody close wewnątrz bloku using.
Cdaragorn

5
@Cdaragorn, dokumenty MSDN są zwykle dość jasne na temat Close () vs Dispose (). Na przykład w przypadku SqlConnection dokumenty mówią, że Close () i Dispose () są funkcjonalnie równoważne. Nie mam żadnych zastrzeżeń co do wywołania Close (), ale wywołania metody Dispose () powinny również istnieć dla wszystkich IDisposables - a najczystszym sposobem na to jest użycie instrukcji using. W przypadkach, w których wiesz, że Dispose () nie wywołuje Close (), powinieneś wywołać Close () w ostatnim bloku, jeśli możesz, a nie w using bloku (więc nadal jest wywoływana, jeśli istnieje wyjątek).
RickNZ

17

Odpowiedź na to pytanie może być dość szeroka.

Zasadniczo główną różnicą dla mnie, która zwykle wpływa na moje decyzje dotyczące używania, jest to, że w przypadku SQLDataReader dane są „przesyłane strumieniowo” z bazy danych. Z SQLDataAdapter wyodrębniasz dane z bazy danych do obiektu, który może być dalej odpytywany, a także wykonywać operacje CRUD.

Oczywiście ze strumieniem danych SQLDataReader jest DUŻO szybszy, ale jednocześnie można przetwarzać tylko jeden rekord. Dzięki SQLDataAdapter masz pełną kolekcję pasujących wierszy do zapytania z bazy danych w celu pracy z / przejścia przez kod.

OSTRZEŻENIE: Jeśli używasz SQLDataReader, ZAWSZE, ZAWSZE, ZAWSZE upewnij się, że piszesz odpowiedni kod, aby zamknąć połączenie, ponieważ utrzymujesz otwarte połączenie z SQLDataReader. Zaniechanie tego lub prawidłowa obsługa błędów w celu zamknięcia połączenia w przypadku błędu w przetwarzaniu wyników spowoduje USZKODZENIE aplikacji z powodu wycieków połączenia.

Przepraszam, mój VB, ale jest to minimalna ilość kodu, którą powinieneś mieć podczas korzystania z SqlDataReader:

Using cn As New SqlConnection("..."), _
      cmd As New SqlCommand("...", cn)

    cn.Open()
    Using rdr As SqlDataReader = cmd.ExecuteReader()
        While rdr.Read()
            ''# ...
        End While
    End Using
End Using     

odpowiednik C #:

using (var cn = new SqlConnection("..."))
using (var cmd = new SqlCommand("..."))
{
    cn.Open();
    using(var rdr = cmd.ExecuteReader())
    {
        while(rdr.Read())
        {
            //...
        }
    }
}

Jeśli Twoim celem jest uzyskanie danych za pomocą zapytania wybierającego w bazie danych i dostęp do tych danych tylko w różnych wierszach, przejdź do rpevious wiersza itp., Możesz użyć SQLDatareader i załadować go do bazy danych za pomocą dtable.Load (rdr). Następnie przeglądaj w górę iw dół w tym pliku danych. Możesz użyć tej metody zamiast DataAdapter ...
zmienna

14

SqlDataAdapter jest zwykle używany do wypełnienia DataSet lub DataTable, dzięki czemu będziesz mieć dostęp do danych po zamknięciu połączenia (rozłączeniu dostępu).

SqlDataReader to połączony kursor tylko do szybkiego przewijania do przodu, który zwykle jest szybszy niż wypełnianie DataSet / DataTable.

Co więcej, dzięki SqlDataReader radzisz sobie z danymi po jednym rekordzie na raz i nie przechowujesz żadnych danych w pamięci. Oczywiście w przypadku DataTable lub DataSet masz narzut alokacji pamięci.

Jeśli nie musisz przechowywać danych w pamięci, więc tylko do renderowania rzeczy, przejdź do SqlDataReader. Jeśli chcesz radzić sobie z danymi w sposób rozłączony, wybierz DataAdapter, aby wypełnić DataSet lub DataTable.


10

Użyj SqlDataAdapter, gdy chcesz wypełnić DataSet / DataTable w pamięci z bazy danych. Dzięki temu masz możliwość zamykania / usuwania połączenia, przekazywania datatable / ustawiania w pamięci. Następnie można manipulować danymi i utrwalać je z powrotem w bazie danych za pomocą adaptera danych w połączeniu z funkcją InsertCommand / UpdateCommand.

Użyj SqlDataReader, gdy chcesz uzyskać szybki dostęp do danych o małej ilości pamięci bez potrzeby elastyczności, np. Przekazywania danych w ramach logiki biznesowej. Jest to bardziej optymalne do szybkiego pobierania dużych ilości danych z niskim zużyciem pamięci, ponieważ nie ładuje wszystkich danych do pamięci za jednym razem - dzięki podejściu SqlDataAdapter DataSet / DataTable zostanie wypełniony wszystkimi danymi, więc jeśli jest dużo wierszy i kolumn, które będą wymagały dużo pamięci do przechowywania.


0

Funkcja Fill używa wewnętrznie DataReader. Jeśli rozważasz „Który z nich jest bardziej wydajny?”, To użycie DataReadera w ścisłej pętli, która wypełnia kolekcję rekord po rekordzie, prawdopodobnie będzie obciążać system tak samo, jak użycie DataAdapter.Fill.

(System.Data.dll, System.Data.Common.DbDataAdapter, FillInternal.)

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.