2010-06-03 65 views
4

如何讓此功能更高效。目前運行時間爲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表定義它們是:

ReportData

ReportID   int 

ReportDataColumn

ReportDataColumnId int 
ReportDataId  int 
Name    varchar(255)  
Value    text  
+2

爲什麼該方法被調用190次?它是否被不必要地調用(你可以先調用它並緩存結果)?它可以並行處理190個不同的報告嗎? – Greg 2010-06-03 18:56:57

+1

是的,這是190個不同的報告,我正在合併成一張桌子。 每個報告可以有不同的列名稱,但也有很多重疊的名稱。 – 2010-06-03 18:59:03

+0

只是要清楚,這是Linq2Sql什麼的?你使用的是什麼版本的.NET? – 2010-06-03 19:30:56

回答

4

我相信你應該能夠簡化功能弄成這個樣子

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

從那裏的名字添加到您的表。

+0

如何從'where'中刪除null測試並在不同的測試之後進行測試? – 2010-06-03 19:06:29

+0

如果有很多重複項,這可能是一個很好的建議。我會移動它。 – 2010-06-03 19:08:08

+0

不錯和短,我想聽到(從OP)探查器認爲它。 – 2010-06-03 19:09:46

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; 
} 

但我不指望一個巨大的進步

+0

這是迄今爲止領先18288毫秒187呼叫 – 2010-06-03 19:22:55

0
  • 重複string.isnullorempty檢查,通過做
  • 你可以擺脫在foreach年代SelectMany(我看到安東尼剛剛發佈相同:)
  • 保持「DataStream」列的相同語義(切換到安東尼的版本後),你可以做新的HashS et(columnsToAdd){「DataStream」},但只需添加(通過concat或union或其他)「DataStream」字符串,然後Distinct()結果並避免HashSet創建(可能同時配置文件)

這可能是矯枉過正這(取決於條目的ReportDatas數,列在每個ReportDataColumns號,主機等),但也有可能並行上的核心數量。

如果你決定並行處理ReportDatas項,例如,你可以有每個人可以創建自己的列集合或把它們都寫成ConcurrentBag認爲,當你完成所有事情或任何事情時,你都會有所區別。

+0

詹姆斯,「DataStream」問題最好解決與一個簡單的如果/然後在最後的DataColumns。 – 2010-06-03 19:32:47

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; 
} 

編輯:我繼續加空,「」到年初設定的散列值,所以我們不再需要爲空或空的檢查。

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分析器發出的查詢。然後前

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

最後分析IO和查詢的時間與這些陳述運行它,你可能需要一個或兩個指數帶來的IO下來。列順序在這裏很重要。

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