2010-03-10 2 views
8

DataReader более эффективен, чем DataTable, если вам нужно показывать данные, но не манипулировать им. Однако, чтобы получить DataReader с уровня доступа к данным, должен ли я оставить объект соединения открытым? Я думаю, что это тоже очень большая проблема с эффективностью. Итак, есть ли другой подход к этому, чтобы в полной мере использовать DataReader?Таблица данных ADO.NET и считыватель данных

ответ

10

Да, устройство чтения данных, безусловно, является наиболее эффективным - но вы делаете не хотите, чтобы соединение открылось в течение длительного периода времени!

  • использовать DataReader для считывания ваших данных в объект сущности; откройте соединение, прочитайте данные, закройте соединение.
  • делать все, что вам нужно, чтобы связать ваш бизнес-объект
  • сохранить изменения обратно, например. используя специальный SQL-запрос, хранимую процедуру или все, что вам нужно; снова: откройте подключение, запишите изменения, закройте соединение

Это, пожалуй, самое эффективное, что вы можете получить - это немного работа, какой-то скучный код и все, но это примерно так же быстро, как и возможно.

Если вы больше заинтересованы в производительности разработчиков, чем в сырой скорости, почему бы не использовать какой-либо ORM, чтобы делать все это скучное, раздражающее отображение взад и вперед? Сохраняет вы много кодирования и беспорядочный материал для поддержания!

+0

Благодарим вас за ответ. Обычно я использую ORM или создаю свой собственный уровень бизнес-логики с объектами сущности. Однако для небольшого проекта я попробовал просто использовать устройство чтения данных. Есть ли что-нибудь, что я могу сделать, кроме объектов orm или entity? – erasmus

+2

@erasmus Если это действительно небольшой проект, не беспокойтесь об эффективности. Просто используйте то, что вам просто легче. Не существует правила, которое должно выполнять каждое приложение, а также возможно. Единственное ожидание заключается в том, что оно выполняется так же хорошо, как и для удовлетворения ожидаемых потребностей. –

+0

@erasmus: согласен с Майком - чем меньше проект, тем менее важным является последний бит производительности. Используйте Linq-to-SQL, NHibernate или что-то в этом роде - это просто * намного легче сделать, что определенно более важно в небольшом проекте –

0

Если вы хотите полностью отвлечь связи и церемонию ADO.NET, DataReader - небольшая задача. Мне действительно не нравится, когда мой инструмент данных имеет открытое соединение на ходу, в надежде DataReader расположен (предполагается, что вы использовали опцию CommandBehavior.CloseConnection). Кроме того, при использовании большого количества DataReaders сложно объединить соединения, поскольку вы не можете ничего сделать с подключением до тех пор, пока предыдущий DataReader не будет закрыт. Они не могут легко пройти. Ваш Data-инструмент не является истинной абстракцией.

С другой стороны, DataTables являются чрезвычайно гибкими и могут создавать очень эффективный, понятный код. Linq-To-DataTable отлично. К счастью, DataTable - actually pretty efficient. Для не-огромных результирующих наборов он почти так же быстро, как и datareader. (это зависит, конечно, от того, что вы делаете.) Все больше и больше я получаю DataTables от своего инструмента обработки данных, а не от читателей. Это действительно делает жизнь простой. Я могу продолжать использовать такое же открытое соединение. В инструменте данных нет «состояния».

Код для получения DataReader очень прост. Поэтому, когда мне действительно нужен DataReader (не часто), я просто позволю своему DAL передать мне мое соединение, и я сам получаю свой DataReader.

+2

DataTables - это ленивый способ вернуть данные и привести к недостижимому коду. Вы должны использовать Readers и возвращать объекты. –

+1

@ Keith Rousseau, похоже, мы собираемся не согласиться. Для создания экземпляра одного или нескольких объектов данные обеспечивают простоту и гибкость. Может быть, вы захотите, чтобы ваши данные были XML? Из DataTable нет проблем. Эффективность, которую вы получаете от DataReaders, часто мала и не стоит того. –

+0

Я могу придумать много примеров. С DataRows вы можете иметь фантастическую гибкость при построении своих объектов; вы можете построить тонну объектов из одного db-запроса и одного оператора LINQ. Эффективность, которую вы получаете от DataReaders, часто мала и не стоит того. Если * lazy * вы имеете в виду построение многих объектов с ** небольшим ** количеством кода, который очень ясен и без возможности младших программистов, оставляющих открытые соединения, тогда да, я ленив. Я хочу, чтобы это было сделано быстро, ясно и без проблем. –

2

Пусть ваш слой данных возвращает объектов, а не для данных или считывателей данных. Я бы предложил вам заполнить ваши объекты с помощью устройства чтения данных.

+0

Достаточно ли моего слоя просмотра узнать о моих объектах домена? – jim

+0

здесь нет объекта домена, если вы имеете в виду объекты. – erasmus

+2

@jim - это совершенно отдельный вопрос, но ответа обычно нет. –

1

Что я обычно делаю, так это открыть читателя с помощью CommandBehavior.CloseConnection. Затем я просматриваю считыватель и считываю данные в свою собственную объектную модель или список или что-то в памяти с данными, а затем закрываю читателя. Он делает многое из того же материала, что и таблица данных, но мне просто не нравится общаться с раздутыми и слабо типизированными структурами данных.

0

Когда я исследовал это раньше, я считаю, что разница в производительности между DataReader и DataTable была тривиальной, за исключением, возможно, очень больших объемов данных.С тех пор я обычно использовал DataTable, поскольку он более полнофункциональный, может работать с отключенным и т. Д.

+1

Каковы были результаты? вы можете нам дать? – erasmus

3

Я никогда не выпускаю DataReader в дикую природу (из DAL). Только вопрос времени, прежде чем вы покидаете связи. Кроме того, я почти никогда не сталкиваюсь с таким количеством данных в одном вызове, где проблема с DataTable или DataSet представляет проблему.

Мы используем объектно-ориентированный язык, и DAL действительно может воспользоваться этим. В вашем проекте должна быть только одна строка кода, которая получает строку подключения. Только один объект, который фактически касается базы данных (вызовы ExecuteNonQuery, DA.Fill() и т. Д.)

Это также позволяет вам довольно активно участвовать в регистрации исключений и т. Д., Потому что вы делаете это только один раз. Поэтому в одном базовом классе DAL, который я использую для всего моего объекта DAL во всем моем проекте, у меня есть логика, что если DAL выдает исключение, то он регистрируется в таблице в моей базе данных. Это протоколирование выходит из строя в текстовом файле, если происходит сбой ведения базы данных.

So the code I see a lot looks like: 
- Start a try block 
- Make a SQLCommand 
- Get connection string. 
- Make Connection object 
- Open the connection 
- Get the data 
- Bind the data 
- Close the connection 
- Log error if exception 

Поскольку я инкапсулировать все это, мой код, чтобы получить данные теперь выглядит следующим образом:

GridView1.DataSource = cProgram.DB.getMyData(); 

(или скорее объект BAL находится между 2). БД - это обычный объект (не статический), но он создается только один раз для каждого приложения.

+0

Что такое бал ?? – nawfal

+0

@nawfal Business Application Layer – JBrooks

+1

никогда не слышал об этом термине. Используется для «бизнес-уровня», «домена», «модели» и т. Д. Надеюсь, они одинаковы. – nawfal

1

Дадим нам глупый тест, чтобы проверить, насколько быстрее работает DataReader (.Net версия 4). Я извлек одну запись из базы данных (SQL Server 2000) и прочитал все ее поля. Я повторил этот процесс 1000 раз. DataReader занял 17.3327585 секунд, а DataTable - 18.37320156, поэтому DataReader на 1.04 секунды быстрее, чем DataTable для 1000 просмотров.

Таким образом, можно получить прирост производительности 0,00104 секунды, если DataReader предпочтительнее DataTable.

Посмотрите на Is DataSet slower than DataReader due to…?, а

0

Straight from the documentation:

Когда вам нужно получить несколько строк данных, так что вы можете дисплей или обрабатывать данные каким-либо другим образом, у вас есть два основных выбор. Вы можете использовать объект DataSet или объект DataReader.

Подход DataReader обычно быстрее, поскольку он позволяет избежать накладных расходов , связанных с созданием объекта DataSet. Накладные расходы , связанные с объектом DataSet, включают в себя создание подбот данных , таких как DataTables, DataRows и DataColumns. Однако DataReader обеспечивает меньшую гибкость и менее подходит к ситуациям, когда вам нужно кэшировать данные и передавать данные в компоненты в приложении с несколькими уровнями.

Примечание: DataAdapter, используемый для заполнения DataSet, использует DataReader внутренне.

Используйте DataReader, если выполняются следующие условия:

• Вам нужно только вперед, только для чтения доступ к данным (шланг сценарий пожара), и вы хотите получить доступ к данным, как быстро по возможности, и , вам не нужно кэшировать его.

• У вас есть контейнер данных, таких как бизнес-компонент, который вы можете поместить данные в

Используйте DataSet, если выполняются следующие условия:.

• Вы должны кэшировать или передавать данные между слоями.

• Вам требуется реляционный вид данных в памяти для XML или не-XML-манипуляции.

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

• Вам необходимо привязать данные к типу управления, с которым DataReader не может привязываться к . Многие элементы управления Windows Forms, способные привязывать данные , требуют источника данных, который реализует интерфейс IList. DataSet реализует IList, но DataReader реализует IEnumerable. IEnumerable поддерживает привязку данных к большинству элементов управления веб-формы, но не к определенным элементам управления Windows Forms. Проверьте требования к источнику данных для конкретного типа управления, который вы хотите связать.

• Вам необходимо получить доступ к нескольким наборам данных одновременно, а вы не хотите хранить открытые ресурсы сервера.

Говоря о DataSet, в основном большая часть из них имеет значение для DataTable. С точки зрения эффективности, here is rare benchmarking from msdn itself. Нижняя строка - DataReader - это немного быстрее, и если это имеет значение.

See this related question тоже, что предлагает некоторые крутые ОРМ и бенчмаркинг.

0

Это то же самое, что я опубликовал here.

Я сделал некоторые бенчмаркинг себя с различными подходами:

public DataTable Read1(string query) 
{ 
    using (var cmd = conn.CreateCommand()) 
    { 
     cmd.CommandText = query; 
     cmd.Connection.Open(); 
     var table = new DataTable(); 
     using (var r = cmd.ExecuteReader()) 
      table.Load(r); 
     return table; 
    } 
} 

public DataTable Read2<S>(string query) where S : IDbDataAdapter, IDisposable, new() 
{ 
    using (var da = new S()) 
    { 
     using (da.SelectCommand = conn.CreateCommand()) 
     { 
      da.SelectCommand.CommandText = query; 
      da.SelectCommand.Connection.Open(); 
      DataSet ds = new DataSet(); 
      da.Fill(ds); 
      return ds.Tables[0]; 
     } 
    } 
} 

public IEnumerable<S> Read3<S>(string query, Func<IDataRecord, S> selector) 
{ 
    using (var cmd = conn.CreateCommand()) 
    { 
     cmd.CommandText = query; 
     cmd.Connection.Open(); 
     using (var r = cmd.ExecuteReader()) 
      while (r.Read()) 
       yield return selector(r); 
    } 
} 

public S[] Read4<S>(string query, Func<IDataRecord, S> selector) 
{ 
    using (var cmd = conn.CreateCommand()) 
    { 
     cmd.CommandText = query; 
     cmd.Connection.Open(); 
     using (var r = cmd.ExecuteReader()) 
      return ((DbDataReader)r).Cast<IDataRecord>().Select(selector).ToArray(); 
    } 
} 

public List<S> Read5<S>(string query, Func<IDataRecord, S> selector) 
{ 
    using (var cmd = conn.CreateCommand()) 
    { 
     cmd.CommandText = query; 
     cmd.Connection.Open(); 
     using (var r = cmd.ExecuteReader()) 
     { 
      var items = new List<S>(); 
      while (r.Read()) 
       items.Add(selector(r)); 
      return items; 
     } 
    } 
} 

1 и 2 возвращает DataTable, а остальные сильно типизированных результирующий набор, поэтому его точно не яблоки с яблоками, но я пока время их соответствующим образом.

Просто предметов первой необходимости:

Stopwatch sw = Stopwatch.StartNew(); 
for (int i = 0; i < 100; i++) 
{ 
    Read1(query); // ~8900 - 9200ms 

    Read1(query).Rows.Cast<DataRow>().Select(selector).ToArray(); // ~9000 - 9400ms 

    Read2<MySqlDataAdapter>(query); // ~1750 - 2000ms 

    Read2<MySqlDataAdapter>(query).Rows.Cast<DataRow>().Select(selector).ToArray(); // ~1850 - 2000ms 

    Read3(query, selector).ToArray(); // ~1550 - 1750ms 

    Read4(query, selector); // ~1550 - 1700ms 

    Read5(query, selector); // ~1550 - 1650ms 
} 

sw.Stop(); 
MessageBox.Show(sw.Elapsed.TotalMilliseconds.ToString()); 

Запрос возвращается около 1200 строк и 5 полей (работать в течение 100 раз). Помимо Read1 все выполнено хорошо. Из всего, что я предпочитаю Read3, который возвращает данные лениво, как перечислены. Это полезно для памяти, если вам нужно только перечислить ее. Чтобы иметь копию коллекции в памяти, вам лучше с Read4 или Read5, как вам будет угодно.

Смежные вопросы