繁体   English   中英

如何提高以下代码的性能?

[英]How can I improve the performance of the following code?

此代码正在运行,但花费了太多时间。 每个数据表都包含 1000 行,每次我需要从另一个数据表中筛选出与列相关的数据。

for (int i = 0; i < dsResult.Tables[0].Rows.Count; i++)
{
    DataTable dtFiltered = dtWorkExp.Clone();

    foreach (DataRow drr in dtWorkExp.Rows)
    {
        if (drr["UserId"].ToString() == dsResult.Tables[0].Rows[i]["Registration NO."].ToString())
        {
            dtFiltered.ImportRow(drr);
        }
    }

    DataTable dtFilteredAward= dtAwards.Clone();

    foreach (DataRow drr in dtAwards.Rows)
    {
        if (drr["UserId"].ToString() == dsResult.Tables[0].Rows[i]["Registration NO."].ToString())
        {
            dtFilteredAward.ImportRow(drr);
        }
    }

    DataTable dtFilteredOtherQual = dtOtherQual.Clone();

    foreach (DataRow drr in dtOtherQual.Rows)
    {
        if (drr["UserId"].ToString() == dsResult.Tables[0].Rows[i]["Registration NO."].ToString())
        {
            dtFilteredOtherQual.ImportRow(drr);
        }
    }

    //Do some operation with filtered Data Tables
}

您可以在 for 循环之外声明这些行。

  DataTable dtFiltered = dtWorkExp.Clone();

您可以将其分配给一个变量并使用它,而不是每次都访问 dsResult.Table[0]。

您也可以用 LINQ 替换 foreach 循环。

将表达式的值放入变量中。

var regNo = dsResult.Tables[0].Rows[i]["Registration NO."].ToString();

将列的索引放入变量中。 按索引访问比按列名更快。

int index = dtWorkExp.Columns["UserId"].Ordinal;

结果代码:

int dtWorkIndex = dtWorkExp.Columns["UserId"].Ordinal;
int dtAwardsIndex = dtAwards.Columns["UserId"].Ordinal;
int dtOtherQualIdex = dtOtherQual.Columns["UserId"].Ordinal;

for (int i = 0; i < dsResult.Tables[0].Rows.Count; i++)
{
    var regNo = dsResult.Tables[0].Rows[i]["Registration NO."].ToString();

    DataTable dtFiltered = dtWorkExp.Clone();

    foreach (DataRow drr in dtWorkExp.Rows)
    {
        if (drr[dtWorkIndex].ToString() == regNo)
        {
            dtFiltered.ImportRow(drr);
        }
    }
    ...

当然,如果您事先确切知道列索引,则可以将其设置为常量。 此外,如果 UserId 索引在所有表中都匹配,则单个变量就足够了。


您也可以尝试使用BeginLoadDataEndLoadData方法。

DataTable dtFiltered = dtWorkExp.Clone();
dtFiltered.BeginLoadData();

foreach (DataRow drr in dtWorkExp.Rows)
{
    if (drr[dtWorkIndex].ToString() == regNo)
    {
        dtFiltered.ImportRow(drr);
    }
}
dtFiltered.EndLoadData();

但我不确定它们是否与ImportRow一起有意义。


最后,并行化会有所帮助。

for (int i = 0; i < dsResult.Tables[0].Rows.Count; i++)
{
    var regNo = ...;

    var workTask = Task.Run(() =>
    {
        DataTable dtFiltered = dtWorkExp.Clone();
    
        foreach (DataRow drr in dtWorkExp.Rows)
        {
            if (drr[dtWorkIndex].ToString() == regNo)
            {
                dtFiltered.ImportRow(drr);
            }
        }
        return dtFiltered;
    });
    
    var awardTask = Task.Run(() =>
        ...
    
    var otherQualTask = Task.Run(() =>
        ...
    
    //Task.WaitAll(workTask, awardTask, otherQualTask);
    await Task.WhenAll(workTask, awardTask, otherQualTask);
    
    //Do some operation with filtered Data Tables
}

我会做什么:

主数据表的所有行都是可枚举的:

var rows = dsResult.Tables[0].AsEnumerable();

获取您要过滤的列:

var filter = rows.Select(r => r.Field<string>("Registration NO."));

创建一个接受该过滤器的方法、一个要过滤的表和一个要比较的字段。

public static DataTable Filter<T>(EnumerableRowCollection<T> filter, DataTable table, string fieldName)
{
    return table.AsEnumerable().Where(r => filter.Contains(r.Field<T>(fieldName))).CopyToDataTable();
}

最后使用方法过滤所有表:

var dtFiltered = Filter<string>(filter, dtWorkExp, "UserId");
var dtFilteredAward = Filter<string>(filter, dtAwards, "UserId");
var dtFilteredOtherQual = Filter<string>(filter, dtOtherQual, "UserId");

加起来就是这样

public void YourMethod()
{
    var rows = dsResult.Tables[0].AsEnumerable();
    var filter = rows.Select(r => r.Field<string>("Registration NO."));
    var dtFiltered = Filter<string>(filter, dtWorkExp, "UserId");
    var dtFilteredAward = Filter<string>(filter, dtAwards, "UserId");
    var dtFilteredOtherQual = Filter<string>(filter, dtOtherQual, "UserId");
}

public static DataTable Filter<T>(EnumerableRowCollection<T> filter, DataTable table, string fieldName)
{
    return table.AsEnumerable().Where(r => filter.Contains(r.Field<T>(fieldName))).CopyToDataTable();
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM