重构 - 速度提升

时间:2010-06-03 18:50:09

标签: c# linq refactoring profiling

如何提高此功能的效率。它目前运行在6 - 45秒。 我已经在这个特定方法上运行了dotTrace探查器,它的总时间在6,000到45,000毫秒之间。大部分时间花在“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表定义,它们是:

ReportData

ReportID            int

ReportDataColumn

ReportDataColumnId  int
ReportDataId        int 
Name                varchar(255)    
Value               text    

5 个答案:

答案 0 :(得分:4)

我相信你应该能够将你的功能简化为类似的东西

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

然后从那里添加名字。

答案 1 :(得分:3)

您的代码(仅)运行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;
}

但我不希望有大的进步

答案 2 :(得分:1)

当你提出问题时,你应该提到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 profiler发出的查询。然后通过在

之前运行这些语句来分析查询的IO和TIME
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)

答案 3 :(得分:0)

  • 重复string.isnullorempty检查
  • 你可以通过做SelectMany摆脱foreach's(我看到Anthony刚刚发布了相同的内容:)。
  • 为“DataStream”列保留相同的语义(在切换到Anthony的版本之后),你可以做新的HashSet(columnsToAdd){“DataStream”}但是添加可能更容易/更快(通过concat或union或者其他)“DataStream”字符串然后Distinct()结果并避免HashSet创建(可能同样配置两者)

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

例如,如果您决定并行处理ReportDatas条目,则可以让每个条目创建自己的列集合,或者让它们全部写入ConcurrentBag,当它完成时或者其他任何内容时,您将不同。

答案 4 :(得分:0)

这可能会对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或为空。