SqlDataAdapter vs SqlDataReader


130

Які відмінності між використанням SqlDataAdapter проти SqlDataReader для отримання даних з БД?

Я спеціально розглядаю їх плюси і мінуси, а також їх швидкість і швидкість роботи в пам'яті.

Дякую

Відповіді:


193

SqlDataReader:

  • Тримає з'єднання відкритим, поки ви не закінчите (не забудьте закрити його!).
  • Зазвичай його можна повторити лише один раз
  • Це не так корисно для оновлення назад до бази даних

З іншого боку, це:

  • Має лише один запис у пам'яті одночасно, а не весь набір результатів (це може бути ВЕЛИЧЕЗНО )
  • Це приблизно так швидко, як ви можете отримати за одну ітерацію
  • Дозволяє швидше розпочати обробку результатів (як тільки буде доступна перша запис). Для деяких типів запитів це також може бути дуже великою справою.

SqlDataAdapter / DataSet

  • Дозволяє вам закрити з'єднання, як тільки воно завантажується, і навіть може автоматично закрити його
  • Усі результати доступні в пам'яті
  • Ви можете повторювати його стільки разів, скільки вам потрібно, або навіть шукати певний запис за індексом
  • Має кілька вбудованих факультетів для оновлення назад до бази даних

Ціною:

  • Набагато більше використання пам'яті
  • Ви чекаєте, поки всі дані будуть завантажені, перш ніж використовувати будь-який з них

Тож насправді це залежить від того, що ви робите, але я, як правило, віддаю перевагу DataReader, поки мені не потрібне щось, що підтримується лише набором даних. SqlDataReader ідеально підходить для загального випадку доступу до даних, прив'язуючи до сітки, доступної лише для читання.

Для отримання додаткової інформації див . Офіційну документацію Microsoft .


5
DataSet - це сховище даних в пам'яті, тоді як читач даних - лише середовище для отримання даних. Якщо легша примітка, ви можете запускати запити Linq на DataSet, але не на пристрої для читання даних.
Партха Чудхурі

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

7
Ця відповідь вводить в оману. Якщо ви обмотаєте свої об'єкти SqlConnection та SqlDataReader за допомогою операторів "using" (як і слід, оскільки вони ідентифікуються), з'єднання буде закрито автоматично. І ви можете використовувати DataSet з SqlDataReader: просто зателефонуйте DataSet.Load (SqlDataReader).
RickNZ

4
@RickNZ Не надто швидко довіряйте, використовуючи заяви, щоб закрити для вас речі. Вони називають метод об'єкта Dispose (), а не метод Close (), і я натрапив на принаймні один випадок, коли Dispose фактично не закрив для мене об'єкт. Завжди найкраще включити явний виклик методу закриття всередині використовуючого блоку.
Cdaragorn

5
@Cdaragorn документи MSDN зазвичай досить чіткі щодо Close () vs. Dispose (). Наприклад, у випадку SqlConnection, документи говорять про те, що Close () та Dispose () функціонально еквівалентні. У мене немає жодних заперечень проти дзвінка Close (), але виклики Dispose () повинні бути присутніми також і для всіх IDisposables - і найчистіший спосіб зробити це з використанням оператора. У випадках, коли ви знаєте, що Dispose () не викликає Close (), тоді вам слід викликати Close () в остаточному блоці, якщо зможете, а не в межах блоку, що використовує (так що він все ще викликається, якщо є виняток).
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())
        {
            //...
        }
    }
}

Якщо ваша мета - отримати дані за допомогою обраного запиту на db, і отримати доступ до цих даних лише в різних рядках, перейти до строкової строки і т.д. Потім перегляньте вгору та вниз всередині цієї даних. Ви можете використовувати цей метод замість 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.