簡體   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