Question

I have wrote a method which return a DataRow as soon as it has been fetched from a IDataReader source (using yield keyword). It works, but it is really slower than filling the DataTable using a SqlDataAdapter.

public static IEnumerable<DataRow> AsEnumerable(this IDataReader source)
{
    //create columns
    DataTable dt = new DataTable(); 
    for (int i = 0; i < source.FieldCount; i++)
    {
        dt.Columns.Add(source.GetName(i), source.GetFieldType(i));
    }

    //fetch data
    object[] data = new object[source.FieldCount];   
    dt.BeginLoadData();
    while (source.Read())
    {
        DataRow dr = dt.NewRow(); //this is very slow, bottleneck ?

        source.GetValues(data); 
        for (int i = 0; i < source.FieldCount; i++)
        {
            dr[i] = data[i];
        }
        dt.Rows.Add(dr);
        yield return dr;
    }
    dt.EndLoadData();
}

Here is the results (250.000 rows, lot of columns) :

00:08:34.652  //using SqlDataAdapter
00:12:95.153  //using method above

How can i make it as fast as using SqlDataAdapter ?

Why i'm using this and not SqlDataAdapter : i'd like to process rows as soon as they came from the source, not to 'block' a very long time and wait for all records to be there.

Maybe there is another way to do this. Note : i cannot simply yield a IDataReader (which is fast and support what i need : accessing the data using Item[ColumnName], because data is going to be acceded by different threads, so i need to copy it somewhere before moving to next row...

Was it helpful?

Solution

I will answer my own question :

A method that will give similar performance as using SqlDataReader is to use DataTable.LoadDataRow(object[] values, bool fAcceptChanges) method. This is the method used internally when a DataTable is populated using Fill() method.

It's fast because it fill DataRow data by accessing some internal fields directly, while using DataRow indexer (eg: dr[i] = value) will do several times some internal checks.

As Lorentz suggested, using ItemArray is faster than indexer but it is still slower than using LoadDataRow().

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top