复制ado.net数据表列表的最快方法

时间:2011-12-28 16:23:02

标签: c# .net ado.net

我有一个像

这样的DataTable列表
List<DataTable> a = new List<DataTable>();

我想对此列表进行深层复制(即复制每个DataTable)。我的代码目前看起来像

List<DataTable> aCopy = new List<DataTable>();
for(int i = 0; i < a.Rows.Count; i++) {
    aCopy.Add(a[i].Copy());
}

性能绝对可怕,我想知道是否有一种已知的方法来加速这样的副本?

编辑:不要担心为什么我有这个或需要这样做,只要接受它是我无法改变的遗留代码库的一部分

4 个答案:

答案 0 :(得分:2)

如果你必须复制数据表,它基本上是N次操作。如果数据表非常大并且导致大量分配,您可以通过一次执行一个部分来加速操作,但是您基本上受到工作集的限制。

答案 1 :(得分:2)

你可以试试以下 - 虽然你的里程可能会有所不同,但它给了我一个性能提升!我已经将它改编为您的示例,以演示如何使用替代机制复制数据表 - 克隆表,然后将数据流传入。您可以轻松地将其放入扩展方法中。

List<DataTable> aCopy = new List<DataTable>(); 
for(int i = 0; i < a.Rows.Count; i++) { 
   DataTable sourceTable = a[i];
   DataTable copyTable = sourceTable.Clone(); //Clones structure
   copyTable.Load(sourceTable.CreateDataReader());
} 

这比以下更快(在我的用例中大约为6):

DataTable copyTable = sourceTable.Clone();
foreach(DataRow dr in sourceTable.Rows)
{
    copyTable.ImportRow(dr);
}

另外,如果我们使用ILSpy查看DataTable.Copy正在做什么:

public DataTable Copy()
{
    IntPtr intPtr;
    Bid.ScopeEnter(out intPtr, "<ds.DataTable.Copy|API> %d#\n", this.ObjectID);
    DataTable result;
    try
    {
        DataTable dataTable = this.Clone();
        foreach (DataRow row in this.Rows)
        {
            this.CopyRow(dataTable, row);
        }
        result = dataTable;
    }
    finally
    {
        Bid.ScopeLeave(ref intPtr);
    }
    return result;
}

internal void CopyRow(DataTable table, DataRow row)
{
    int num = -1;
    int newRecord = -1;
    if (row == null)
    {
        return;
    }
    if (row.oldRecord != -1)
    {
        num = table.recordManager.ImportRecord(row.Table, row.oldRecord);
    }
    if (row.newRecord != -1)
    {
        if (row.newRecord != row.oldRecord)
        {
            newRecord = table.recordManager.ImportRecord(row.Table, row.newRecord);
        }
        else
        {
            newRecord = num;
        }
    }
    DataRow dataRow = table.AddRecords(num, newRecord);
    if (row.HasErrors)
    {
        dataRow.RowError = row.RowError;
        DataColumn[] columnsInError = row.GetColumnsInError();
        for (int i = 0; i < columnsInError.Length; i++)
        {
            DataColumn column = dataRow.Table.Columns[columnsInError[i].ColumnName];
            dataRow.SetColumnError(column, row.GetColumnError(columnsInError[i]));
        }
    }
}

手术需要很长时间,这并不奇怪;不仅是一行一行,而且还做了额外的验证。

答案 2 :(得分:0)

您应该指定列表的容量,否则必须在内部增长以容纳数据。有关详细说明,请参阅here

List<DataTable> aCopy = new List<DataTable>(a.Count);

答案 3 :(得分:0)

如果您的搜索条件很简单,我发现以下方法比其他过滤LINQ等记录方式更有效:

    public static DataTable FilterByEntityID(this DataTable table, int EntityID)
    {
        table.DefaultView.RowFilter = "EntityId = " + EntityID.ToString();
        return table.DefaultView.ToTable();
    }