簡體   English   中英

如何使用 DataTable 和 Linq 優化代碼?

[英]How to optimize a code using DataTable and Linq?

我有 2 個數據表 大約有17000條(table1)100000條(table2)記錄。

需要檢查字段“FooName”是否包含“ ItemName ”。 還需要取“FooId” ,然后將“ItemId”“FooId”添加到 ConcurrentDictionary。

我有這個代碼。

DataTable table1;
DataTable table2;           
var table1Select = table1.Select();

ConcurrentDictionary<double, double> compareDictionary = new ConcurrentDictionary<double, double>();

foreach (var item in table1)
{
         var fooItem = from foo in table2.AsEnumerable()
                  where foo.Field<string>("FooName").Contains(item.Field<string>("ItemName"))
                  select foo.Field<double>("FooId");
         if(fooItem != null && fooItem.FirstOrDefault() != 0)
                {
                    compareDictionary.TryAdd(item.Field<double>("ItemId"), fooItem.FirstOrDefault());
                }
}

它工作緩慢(執行任務大約需要 10 分鍾)。

我想讓它更快。 我該如何優化它?

我看你可以攻擊三點:

  1. 放棄對字段訪問器的強類型,轉而支持直接強制轉換:它強制拆箱,您可以完全避免doubles是值類型。 upd正如評論中指出的那樣,無論哪種方式都不會避免取消裝箱,但可能會節省一些方法調用開銷(這也是有爭議的)。 這點大概可以忽略
  2. 緩存引用字符串,因此每個外循環只能訪問一次
  3. (我認為這是最大的收益所在)因為您似乎總是采用第一個結果 - 在 LINQ 中直接選擇FirstOrDefault() - 不要讓它在找到匹配項時枚舉整個事情
ConcurrentDictionary<double, double> compareDictionary = new ConcurrentDictionary<double, double>();

foreach (var item in table1)
    {
        var sample = (string)item["ItemName"]; // cache the value before looping through inner collection
        var fooItem = table2.AsEnumerable()
                            .FirstOrDefault(foo => ((string)foo["FooName"]).Contains(sample)); // you seem to always take First item, so you could instruct LINQ to stop after a match is found
        if (fooItem != null && (double)fooItem["FooId"] != 0)
        {
            compareDictionary.TryAdd((double)item["ItemId"], (double)fooItem["FooId"]);
        }
    }

看來,將.FirstOrDefault()條件應用於 LINQ 查詢語法無論如何都會將其簡化為方法鏈語法,所以我會一直選擇方法鏈,讓您自己來弄清楚美學

如果您願意為了速度而犧牲內存,那么從DataTable轉換為您需要的字段可以比重復從table2提取列數據的速度提高大約 6 倍。 (這是對使用FirstOrDefault的加速的FirstOrDefault 。)

var compareDictionary = new ConcurrentDictionary<double, double>();

var t2e = table2.AsEnumerable().Select(r => (FooName: r.Field<string>("FooName"), FooId: r.Field<double>("FooId"))).ToList();
foreach (var item in table1.AsEnumerable().Select(r => (ItemName: r.Field<string>("ItemName"), ItemId: r.Field<double>("ItemId")))) {
    var firstFooId = t2e.FirstOrDefault(foo => foo.FooName.Contains(item.ItemName)).FooId;

    if (firstFooId != 0.0) {
        compareDictionary.TryAdd(item.ItemId, firstFooId);
    }
}

我使用 C# ValueTuple來避免匿名類的引用對象開銷。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM