Performance 如何快速查找已加载实体列表中的项目

Performance 如何快速查找已加载实体列表中的项目,performance,entity-framework,c#-4.0,collections,Performance,Entity Framework,C# 4.0,Collections,我已经构建了一个MVC5应用程序,使用EF6查询数据库。一页显示两个维度的交叉表:物质与这些物质的性质。它呈现为html表。许多单元格没有值。这就是它看起来的样子: sub 1 sub 2 sub 3 prop A 1.0 prop B 1.5 X prop C 0.6 Y 单元值实际上更复杂,包括工具提示、脚注等 我通过以下步骤实现了html表的生成: 创建一个独特属性的列表; 创建独特物质的列表; 循环遍历属性;

我已经构建了一个MVC5应用程序,使用EF6查询数据库。一页显示两个维度的交叉表:物质与这些物质的性质。它呈现为html表。许多单元格没有值。这就是它看起来的样子:

        sub 1  sub 2  sub 3
prop A   1.0
prop B          1.5     X
prop C   0.6            Y
单元值实际上更复杂,包括工具提示、脚注等

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

创建一个独特属性的列表; 创建独特物质的列表; 循环遍历属性; 为每个渲染一行; 通过物质循环; 查看属性和物质的组合是否有价值; 渲染单元格的值或空值。 使用ANTS performance profiler,我发现step 6存在巨大的性能问题,物质和属性的数量不断增加,命中率激增至数亿,数百种物质和几十种属性是用户可以进行的最大选择。执行时间为几分钟。它似乎可以缩放n实体^2*n属性^2

代码如下所示:

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

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

我可以试着改进什么?我想:

创建某种C对象,使用substance.Id和property.Id作为复合键,并从List对象填充它。哪一个最快? 创建一些Linq查询,该查询返回一个已经包含空单元格的对象,如substance cross join properties left join值。我可以在SQL中轻松地实现这一点,但这可以通过Linq实现吗?存储结果的对象是否可以将该值作为成员字段,以便我仍然可以使用它渲染单元格? 停止预加载,只需对每个组合的值运行数据库查询,这可能得益于数据库索引。 我正在考虑限制用户可以选择的物质和属性的数量,但我不想这样做。 附加信息

应C.Zonnenberg的要求,提供了有关查询的更多信息

填充值列表的查询基本如下: 我创建了一个IQueryable,为其添加所需物质和属性的过滤器。然后,我将在相关实体中发现的物质、属性和价值详细信息包括在内。然后执行query.ToList。正如SQL探查器所看到的那样,实际的SQL查询看起来很复杂,包含SubstanceId IN和PropertyId IN,但执行所需的时间远远少于一秒钟


它返回一个代理列表,比如:{System.Data.Entity.DynamicProxies.SubstancePropertyValue_078F758A4FF9831024D2690C4B546F07240FAC82A1E9D95D3826A834DCD91D1E}

我认为您的最佳选择是第一个选项。但为了高效地执行此操作,我还将修改源数据值并将其转换为字典,这样您就有了一个针对索引查找进行优化的结构:

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

此外,通过在所有物质中循环获取单元格值,您可能会从并行化中获益。

如何填充“values”变量?你能把它添加到你的问题中吗?一个修改稍微减轻了痛苦:我现在使用以下选项:Value currentValue=values.Whereval=>val.substanceId==currentSubstanceId&&val.propertyId==currentPropertyId.SingleOrDefault;,其中使用基本实体中的外键,而不是所包含实体的主键。这会将速度提高约10倍,但不会增加大量调用。这些值是否包括property和substance对象?如果通过延迟加载获取它们,速度会非常慢。@GertArnold,它们包含在值中,但也显式包含在查询中,因此它们会一次全部加载,正如我使用SQL探查器验证的那样。此解决方案工作得非常好。最大可能的选择所需的CPU时间已从几分钟降至20毫秒左右!对于感兴趣的人,我使用了var dict=values.todictionalye=>,e=>e;,为了使整个对象在查找时可用。感谢您建议Parallel.ForEach。但是,我不愿意开始使用并行类,因为目前性能还不错,我不确定需要了解哪些陷阱,我想知道如果许多用户向我的web服务器发送请求,它是否会提高速度。
Value currentValue ;
dict.TryGetValue(Tuple.Create(currentSubstanceId, currentPropertyId), 
                 out currentValue );