我怎样才能快速查找加载实体列表中的项目

How could I quickly look-up items in a List of loaded entities

我构建了一个 MVC 5 应用程序,使用 EF 6 查询数据库。一页显示二维交叉 table:物质与这些物质的特性。它呈现为 html table.Many 单元格没有值。这是它的样子:

        sub 1  sub 2  sub 3
prop A   1.0
prop B          1.5     X
prop C   0.6            Y

单元格的值其实更复杂,包括工具提示、脚注等

我通过以下步骤实现了htmltable的生成:

  1. 创建独特属性列表;
  2. 创建独特物质清单;
  3. 遍历属性;
  4. 为每个渲染一行;
  5. 遍历物质;
  6. 看看属性和物质的组合是否有值;
  7. 呈现单元格的值或空值。

使用 ANTS 性能分析器,我发现第 6 步有一个巨大的性能问题,随着物质和属性的数量增加,命中数爆炸到数亿,有几百种物质和几十种属性(用户可以制造的最大 selection)。执行时间是很多分钟。它似乎可以扩展 N(substances)^2 * N(properties)^2。

代码如下:

Value currentValue = 
values.Where(val => val.substance.Id == currentSubstanceId 
&& val.property.Id == currentPropertyId).SingleOrDefault();

其中值是一个列表,值是一个实体,我从中读取以呈现单元格。值已从数据库中预加载,SQL Server Profiler 未显示任何查询。

由于并非所有单元格都有值,我认为最好遍历行和列并查看是否有值。我不能只循环遍历值列表。

我可以尝试改进什么?我考虑过:

  1. 创建某种 C# 对象,使用 substance.Id 和 property.Id 作为复合键并从 List 对象填充它。哪个最快?
  2. 创建一些 Linq 查询,其中 returns 一个已经包含空单元格的对象,例如(物质交叉连接属性)左连接值。我可以在 SQL 中轻松做到这一点,但是这可以用 Linq 完成吗?存储结果的对象是否可以将值作为成员字段,以便我仍然可以使用它来呈现单元格?
  3. 停止预加载,只 运行 数据库查询每个组合的值,可能受益于数据库索引。
  4. 我正在考虑限制用户可能使用的物质和属性的数量 select,但我宁愿不这样做。

附加信息

根据 C.Zonnenberg 的要求,提供有关查询的更多信息。

填充值列表的查询基本上如下: 我创建了一个 IQueryable,我在其中添加了针对请求的物质和属性的过滤器。然后,我包括在相关实体中找到的物质 属性 和价值详细信息。然后我执行 query.ToList()。 SQL 探查器所见的实际 SQL 查询看起来很复杂,涉及 SubstanceId IN () 和 PropertyId IN (),但执行时间远少于一秒。

它 returns 代理列表,例如:{System.Data.Entity.DynamicProxies.SubstancePropertyValue_078F758A4FF9831024D2690C4B546F07240FAC82A1E9D95D3826A834DCD91D1E}

我认为您最好的选择是您的第一选择。但是为了有效地做到这一点,我还会修改源数据 (values) 并将其转换为字典,这样您就有了一个针对索引查找进行了优化的结构:

var dict = values.ToDictionary(e => 
                       Tuple.Create(e.substance.id, e.propertyid),
                       e => e.Value);

然后对于每个单元格:

Value currentValue ;
dict.TryGetValue(Tuple.Create(currentSubstanceId, currentPropertyId), 
                 out currentValue );

此外,例如,您可以通过在 Parallel.ForEach 循环遍历所有物质中获取单元格值来受益于并行化。