SqlDataAdapter против SqlDataReader


130

В чем разница между использованием SqlDataAdapter и SqlDataReader для получения данных из БД?

Я специально изучаю их плюсы и минусы, а также их скорость и производительность памяти.

Спасибо

Ответы:


193

SqlDataReader:

  • Удерживает соединение открытым до тех пор, пока вы не закончите (не забудьте закрыть его!).
  • Обычно может повторяться только один раз
  • Не так полезно для обновления обратно в базу данных

С другой стороны, это:

  • Только одна запись в памяти за раз, а не весь набор результатов (это может быть ОГРОМНЫМ )
  • Примерно так быстро, как вы можете получить за одну итерацию
  • Позволяет начать обработку результатов раньше (после того, как станет доступна первая запись). Для некоторых типов запросов это тоже может иметь большое значение.

SqlDataAdapter / DataSet

  • Позволяет закрыть соединение, как только оно загрузит данные, и может даже закрыть его для вас автоматически
  • Все результаты доступны в памяти
  • Вы можете перебирать его столько раз, сколько вам нужно, или даже искать конкретную запись по индексу
  • Имеет некоторые встроенные возможности для обновления обратно в базу данных

По цене:

  • Намного более высокое использование памяти
  • Вы ждете, пока все данные будут загружены, прежде чем использовать их

На самом деле это зависит от того, что вы делаете, но я предпочитаю DataReader, пока мне не понадобится что-то, что поддерживается только набором данных. SqlDataReader идеально подходит для общего случая доступа к данным при привязке к сетке только для чтения.

Для получения дополнительной информации см. Официальную документацию Microsoft .


5
DataSet - это хранилище данных в памяти, тогда как datareader - это просто средство для извлечения данных. Отметим, что вы можете запускать запросы Linq в DataSet, но не в устройстве чтения данных.
— Partha Choudhury

Фактически, с небольшим дополнительным кодом вы, безусловно, можете запускать запросы linq (или, по крайней мере, один запрос) на устройстве чтения данных. Просто используйте блок итератора, чтобы вернуть преобразование DataReader в виде IDataRecord внутри вашего while (reader.Read())цикла.
— Joel Coehoorn

7
Этот ответ вводит в заблуждение. Если вы заключите свои объекты SqlConnection и SqlDataReader с помощью операторов using (как и следовало бы делать в любом случае, поскольку они являются IDisposable), соединение будет закрыто автоматически. И вы можете использовать DataSet с SqlDataReader: просто вызовите DataSet.Load (SqlDataReader).
— RickNZ

4
@RickNZ Не спешите доверять выражениям using, чтобы закрыть для вас вещи. Они вызывают метод объекта Dispose (), а не метод Close (), и я столкнулся по крайней мере с одним случаем, когда Dispose фактически не закрыл для меня объект. Всегда лучше включать явный вызов метода close внутри блока using.
— Cdaragorn

5
@Cdaragorn документация MSDN обычно довольно четко описывает Close () и Dispose (). Например, в случае SqlConnection в документации говорится, что Close () и Dispose () функционально эквивалентны. У меня нет возражений против вызова Close (), но вызовы Dispose () также должны присутствовать для всех IDisposables - и самый простой способ сделать это - использовать оператор using. В случаях, когда вы знаете, что Dispose () не вызывает Close (), вам следует вызвать Close () в блоке finally, если вы можете, а не в блоке using (так что он все равно вызывается, если есть исключение).
— RickNZ

17

Ответ на это может быть довольно широким.

По сути, для меня главное отличие, которое обычно влияет на мои решения о том, какой использовать, состоит в том, что с помощью SQLDataReader вы «передаете» данные из базы данных. С помощью SQLDataAdapter вы извлекаете данные из базы данных в объект, который сам может запрашиваться дальше, а также выполняете операции CRUD.

Очевидно, что с потоком данных SQLDataReader работает НАМНОГО быстрее, но вы можете обрабатывать только одну запись за раз. С помощью SQLDataAdapter у вас есть полная коллекция строк, соответствующих вашему запросу из базы данных, для работы с вашим кодом / передачи кода.

ПРЕДУПРЕЖДЕНИЕ. Если вы используете SQLDataReader, ВСЕГДА, ВСЕГДА, ВСЕГДА убедитесь, что вы пишете правильный код для закрытия соединения, поскольку вы сохраняете соединение открытым с помощью SQLDataReader. Несоблюдение этого правила или надлежащая обработка ошибок для закрытия соединения в случае ошибки при обработке результатов ЗАКРЫТ ваше приложение утечками соединения.

Простите мой VB, но это минимальный объем кода, который вы должны иметь при использовании 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     

эквивалентный C #:

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

Если ваша цель - получить данные с помощью запроса выбора в базе данных и получить доступ к этим данным только в разных строках, перейти к предыдущей строке и т.д., вы можете использовать SQLDatareader и загрузить его в таблицу данных с помощью dtable.Load (rdr). Затем просмотрите эту таблицу данных вверх и вниз. Вы можете использовать этот метод вместо DataAdapter ...
— переменная

14

SqlDataAdapter обычно используется для заполнения DataSet или DataTable, поэтому у вас будет доступ к данным после закрытия вашего соединения (отключенный доступ).

SqlDataReader - это подключенный курсор только для быстрой перемотки вперед, который обычно работает быстрее, чем заполнение DataSet / DataTable.

Более того, с помощью SqlDataReader вы обрабатываете данные по одной записи за раз и не храните никаких данных в памяти. Очевидно, что с DataTable или DataSet у вас есть накладные расходы на выделение памяти.

Если вам не нужно хранить данные в памяти, поэтому для рендеринга используйте только SqlDataReader. Если вы хотите работать с данными в отключенном режиме, выберите DataAdapter, чтобы заполнить DataSet или DataTable.


10

Используйте SqlDataAdapter, если вы хотите заполнить DataSet / DataTable в памяти из базы данных. Затем у вас есть возможность закрыть / удалить соединение, передать данные / установить в памяти. Затем вы можете манипулировать данными и сохранять их обратно в БД с помощью адаптера данных в сочетании с InsertCommand / UpdateCommand.

Используйте SqlDataReader, если вам нужен быстрый доступ к данным с малым объемом памяти без необходимости гибкости, например, для передачи данных по вашей бизнес-логике. Это более оптимально для быстрого извлечения больших объемов данных с низким использованием памяти, поскольку он не загружает все данные в память за один раз - с подходом SqlDataAdapter DataSet / DataTable будет заполнен всеми данными, поэтому, если там много строк и столбцов, для хранения которых потребуется много памяти.


0

Функция Fill внутренне использует DataReader. Если ваше соображение - «Какой из них более эффективен?», То использование DataReader в замкнутом цикле, заполняющем коллекцию запись за записью, вероятно, будет такой же нагрузкой на систему, как и использование DataAdapter.Fill.

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.