如何使用Linq索引查询列表?

时间:2017-12-11 06:15:08

标签: c# performance list linq

我有一个包含8个字段的DTO列表,列表中有477.000条记录从XML文件加载,当我在此列表中过滤项目时,CPU在一个核心中消耗了25%,我认为这种行为是因为List没有编入索引,是否列出了可靠的索引?

DTO

public class PriceDto
{
    public string Filter { get; set; }
    public string Material { get; set; }
    public string Value { get; set; }
    public string Currency { get; set; }
    public string Max { get; set; }
    public string Min { get; set; }
    public string PorcentValue { get; set; }
    public string PromotionPrice { get; set; }
    public string ConditionClass { get; set; }
    public string Vat { get; set; }
}

Linq查询

Price = AllPrices.FirstOrDefault(x => x.Filter == FilterId.ConsecutiveFilter.Trim() &&
x.ConditionClass == accessSequenceItem.PriceCondition &&
x.Material == CodeMaterial);

1 个答案:

答案 0 :(得分:1)

您可以使用LINQ创建LookupDictionary<Lookup>甚至Dictionary<Dictionary<Lookup>>,然后将其用于查询。这会占用时间空间,但改进实际上取决于不同领域中值的分布。在100个过滤器,100种材料和25种条件的随机样本数据集中有500,000个,对过滤器和材料进行索引可以产生2000个随机查询的最快结果,比普通查询快约33倍。通过查找,对不存在的数据的查询速度提高了60到800倍。

以下是创建双索引结构的代码:

var filterMaterialMap = AllPrices.GroupBy(ap => ap.Filter).ToDictionary(apfg => apfg.Key, apfg => apfg.ToLookup(ap => ap.Material));

您运行如下查询:

PriceDto Price = null;
if (filterMaterialMap.TryGetValue(FilterId.ConsecutiveFilter.Trim(), out var matDict))
    Price = matDict[CodeMaterial].FirstOrDefault(ap => ap.ConditionClass == accessSequenceItem.PriceCondition);

其他案例是单个字段索引:

var filterMap = AllPrices.ToLookup(ap => ap.Filter);
var Price = filterMap[FilterId.ConsecutiveFilter.Trim()].FirstOrDefault(ap => ap.Material == CodeMaterial && ap.ConditionClass == accessSequenceItem.PriceCondition);

并将所有三个字段编入索引:

var filterMaterialConditionMap = AllPrices.GroupBy(ap => ap.Filter)
                                          .ToDictionary(apfg => apfg.Key, apfg => apfg.GroupBy(ap => ap.Material)
                                                                                      .ToDictionary(apfmg => apfmg.Key, apfmg => apfmg.ToLookup(ap => ap.ConditionClass)));
PriceDto Price = null;
if (filterMaterialConditionMap.TryGetValue(FilterId.ConsecutiveFilter.Trim(), out var matDict))
    if (matDict.TryGetValue(CodeMaterial, out var condDict))
        Price = condDict[accessSequenceItem.PriceCondition].FirstOrDefault();