Является ли datareader быстрее, чем набор данных при заполнении данных?

Что было бы быстрее.

1) Зацикливание datareader и создание пользовательских строк и столбцов, заполняемых datatable

2) Или создайте объект dataAdapter и просто (.Fill) с данными.

Сохраняется ли производительность datareader при динамическом создании данных?

Ответ 1

DataAdapter использует DataReader под капотом, поэтому ваш опыт, вероятно, будет таким же.

Преимущество DataAdapter заключается в том, что вы вырезали много кода, требующего обслуживания.

Эта дискуссия является немного религиозной проблемой, поэтому обязательно осмотритесь и решите, что лучше всего подходит для вашей ситуации:

Ответ 2

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

Да, в некоторых случаях вы можете получить небольшую экономию с помощью DataReader - и, в частности, если вы хотите передавать данные, это может быть полезно, но если вам действительно нужно все это, я бы придерживался простейшего кода, Если вы считаете, что совокупность данных DataSet вызывает значительную проблему с производительностью, профилируйте ее, а затем попытайтесь ее улучшить.

Ответ 3

Ваш вариант №1 будет медленнее. Однако есть лучший способ конвертировать datareader в datatable, чем добавлять пользовательские строки вручную:

DataTable dt = new DataTable();

using (SqlConnection conn = GetOpenSqlConnection())
using (SqlCommand cmd = new SqlCommand("SQL Query here", conn)
using (IDataReader rdr = cmd.ExecuteReader())
{
    dt.Load(rdr);
}

Я не могу прокомментировать разницу между этим и использованием .Fill().

Ответ 4

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

Ответ 5

Датчик данных быстрее. И если вы используете 2.0+, вам, вероятно, даже не придется использовать datatable. Вы можете использовать общий список вашего объекта.

Ответ 6

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

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

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

Подробнее об этой теме в журнале MSDN

Ответ 7

Как и во многих вопросах, таких как ответ: зависит.

Если вы не знаете структуру своих данных и создаете "TableAdapters" на лету, тогда динамический DataTable будет более эффективным. Существует большое количество генерации кода, участвующих в создании TableAdapter.

Однако, если вы знаете структуру своих данных спереди, тогда возникает вопрос, насколько мне нужна функциональность?

Если вам нужна полная реализация CRUD, тогда есть некоторая эффективность, полученная с помощью TableAdapter, а не для написания всего этого кода CRUD. Кроме того, реализация TableAdapter в порядке (невелика). Если вам нужно что-то более эффективное, вам может быть лучше использовать nHibernate или какой-либо другой ORM.

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

Ответ 8

Переход на DataReader Read, который представляет собой подход только по принципу "только для прямого доступа", который читает данные последовательно, чтобы вы получали записи, как только они были прочитаны при подключении, будут лучшее для памяти и производительности.

Таким образом, между двумя подходами я нахожу IDataAdapter.Fill намного быстрее, чем DataTable.Load. Конечно, это зависит от реализаций. Вот эталонная точка между двумя, которые я разместил здесь:

public DataTable Read1<T>(string query) where T : IDbConnection, new()
{
    using (var conn = new T())
    {
        using (var cmd = conn.CreateCommand())
        {
            cmd.CommandText = query;
            cmd.Connection.ConnectionString = _connectionString;
            cmd.Connection.Open();
            var table = new DataTable();
            table.Load(cmd.ExecuteReader());
            return table;
        }
    }
}

public DataTable Read2<S, T>(string query) where S : IDbConnection, new() 
                                           where T : IDbDataAdapter, IDisposable, new()
{
    using (var conn = new S())
    {
        using (var da = new T())
        {
            using (da.SelectCommand = conn.CreateCommand())
            {
                da.SelectCommand.CommandText = query;
                da.SelectCommand.Connection.ConnectionString = _connectionString;
                DataSet ds = new DataSet(); //conn is opened by dataadapter
                da.Fill(ds);
                return ds.Tables[0];
            }
        }
    }
}

Второй подход всегда превосходил первый.

Stopwatch sw = Stopwatch.StartNew();
DataTable dt = null;
for (int i = 0; i < 100; i++)
{
    dt = Read1<MySqlConnection>(query); // ~9800ms
    dt = Read2<MySqlConnection, MySqlDataAdapter>(query); // ~2300ms

    dt = Read1<SQLiteConnection>(query); // ~4000ms
    dt = Read2<SQLiteConnection, SQLiteDataAdapter>(query); // ~2000ms

    dt = Read1<SqlCeConnection>(query); // ~5700ms
    dt = Read2<SqlCeConnection, SqlCeDataAdapter>(query); // ~5700ms

    dt = Read1<SqlConnection>(query); // ~850ms
    dt = Read2<SqlConnection, SqlDataAdapter>(query); // ~600ms

    dt = Read1<VistaDBConnection>(query); // ~3900ms
    dt = Read2<VistaDBConnection, VistaDBDataAdapter>(query); // ~3700ms
}
sw.Stop();
MessageBox.Show(sw.Elapsed.TotalMilliseconds.ToString());

Read1 выглядит лучше на глазах, но адаптер данных работает лучше (не путать, что один db превосходил другой, все были разные запросы). Однако разница между ними зависела от запроса. Причина может заключаться в том, что Load требует, чтобы различные ограничения проверялись по строке из документации при добавлении строк (его метод на DataTable), а Fill - в DataAdapters, которые были предназначены именно для этого - быстрое создание DataTables.