linq 重构-提高速度

ogq8wdun  于 2022-12-06  发布在  其他
关注(0)|答案(5)|浏览(126)

我如何才能使这个函数更高效呢?它目前的运行时间为6 - 45秒。我已经在这个特定的方法上运行了dotTrace分析器,它的总时间在6,000ms到45,000ms之间。大部分时间都花在了"MoveNext"和"GetEnumerator"调用上。
例如

71.55% CreateTableFromReportDataColumns - 18, 533* ms - 190 calls
 -- 55.71% MoveNext - 14,422ms - 10,775 calls

我能做些什么来加速这个方法吗?它被调用了很多次,并且秒数加起来:

private static DataTable CreateTableFromReportDataColumns(Report report)
    {
        DataTable table = new DataTable();
        HashSet<String> colsToAdd = new HashSet<String> { "DataStream" };
        foreach (ReportData reportData in report.ReportDatas)
        {
            IEnumerable<string> cols = reportData.ReportDataColumns.Where(c => !String.IsNullOrEmpty(c.Name)).Select(x => x.Name).Distinct();

            foreach (var s in cols)
            {
                if (!String.IsNullOrEmpty(s))
                    colsToAdd.Add(s);
            }
        }

        foreach (string col in colsToAdd)
        {
            table.Columns.Add(col);
        }

        return table;
    }

如果需要sql表定义,请在此处输入:

    • 报表数据**
ReportID            int
    • 报表数据列**
ReportDataColumnId  int
ReportDataId        int 
Name                varchar(255)    
Value               text
cnjp1d6j

cnjp1d6j1#

我相信你应该可以把你的函数简化成这样

var columnsToAdd = report.ReportDatas
                    .SelectMany(r => r.ReportDataColumns)
                    .Select(rdc => rdc.Name)
                    .Distinct()
                    .Where(name => !string.IsNullOrEmpty(name));

然后将这些名字添加到您的表中。

t5zmwmid

t5zmwmid2#

您的代码(仅)运行foreach循环,因此得出该方法大部分时间都在MoveNext()等中的结论并不奇怪。
您正在isnullOrEmpty和Distinct(由HashSet重复)上执行双重操作。
我的版本是:

private static DataTable CreateTableFromReportDataColumns(Report report)
{
    DataTable table = new DataTable();
    HashSet<String> colsToAdd = new HashSet<String> { "DataStream" };
    foreach (ReportData reportData in report.ReportDatas)
    {

        foreach (var column in reportData.ReportDataColumns)
        {
            if (!String.IsNullOrEmpty(column.Name))
                colsToAdd.Add(column.Name);
        }
    }

    foreach (string col in colsToAdd)
    {
        table.Columns.Add(col);
    }

    return table;
}

但我并不指望

voase2hg

voase2hg3#

您应该在提出问题时提到LinqToSql,这样您就会得到一些响应来查看您的数据库,看看它是长时间运行的查询还是重复的往返查询

private static DataTable CreateTableFromReportDataColumns(Report report) 
{ 
    DataTable table = new DataTable(); 
    table.Columns.Add("DataStream");
    IEnumerable<string> moreColumns = report.ReportDatas
      .SelectMany(z => z.ReportDataColumns)
      .Select(x => x.Name)
      .Where(s => s != null && s != "")
      .Distinct();

    foreach (string col in moreColumns) 
    { 
        table.Columns.Add(col); 
    } 

    return table; 
}

另外,使用sql事件探查器捕获发出的查询。

SET STATISTICS TIME ON
SET STATISTICS IO ON
  --your query here

最后,您可能需要一个或两个索引来降低IO。列顺序在这里很重要。

CREATE INDEX IX1_ReportData ON ReportData(ReportID, Id)
CREATE INDEX IX1_ReportDataColumn ON ReportDataColumn(ReportDataId, Name)
ryhaxcpt

ryhaxcpt4#

这可能是Hank代码的一点改进,它利用了HashSet会告诉你Add操作是否成功或者元素是否已经存在的事实。

private static DataTable CreateTableFromReportDataColumns(Report report)
{
    HashSet<string> uniqueNames = new HashSet<string> { null, "", "DataStream" };

    DataTable table = new DataTable();
    table.Columns.Add("DataStream");

    foreach (ReportData reportData in report.ReportDatas)
    {
        foreach (var dataColumn in reportData.ReportDataColumns)
        {
            if (uniqueNames.Add(dataColumn.Name))
            {
                table.Columns.Add(dataColumn.Name);
            }
        }
    }

    return table;
}

**编辑:**我在开始时将null和“”添加到散列集,因此我们不再需要检查null或empty。

jdgnovmf

jdgnovmf5#

  • 重复执行字符串. isnullore空检查
  • 你可以通过SelectMany来摆脱foreach(我看到Anthony刚刚发布了同样的帖子:)
  • 为了保持“DataStream”列的相同语义(在切换到Anthony的版本之后),您可以执行new HashSet(columnsToAdd){“DataStream”},但是添加(通过concat或union或其他方式)“DataStream”字符串,然后使用Distinct()方法添加结果并避免创建HashSet可能会更容易/更快(也可以分析两者)

这样做可能有些过头(取决于ReportDatas中的条目数、每个ReportDataColumns中的列数、主机上的内核数等),但您也可以进行并行化。

例如,如果您决定并行处理ReportDatas条目,您可以让每个条目创建自己的列集合,或者让它们全部写入ConcurrentBag,在完成所有操作后使用Distinct或执行其他操作。

相关问题