我已经构建了一个MVC 5应用程序,使用EF 6来查询数据库。一页显示两个维度的交叉表:针对这些物质的特性的物质。它呈现为一个html表。许多单元格没有值。这就是它的样子:
sub 1 sub 2 sub 3
prop A 1.0
prop B 1.5 X
prop C 0.6 Y
单元格值实际上更复杂,包括工具提示,脚注等。
我通过以下步骤实现了html表的生成:
使用ANTS性能分析器,我发现步骤6存在巨大的性能问题,物质和性质数量不断增加,命中数量猛增至数亿,数百种物质和数十种物质(用户可以做出的最大选择)。执行时间是几分钟。它似乎比例N(物质)^ 2 * N(属性)^ 2。
代码如下:
Value currentValue =
values.Where(val => val.substance.Id == currentSubstanceId
&& val.property.Id == currentPropertyId).SingleOrDefault();
其中values是List,Value是一个实体,我从中读取以呈现单元格。值已从数据库预加载,SQL Server Profiler不显示任何查询。
由于并非所有单元格都有值,我认为最好循环遍历行和列,看看是否有值。我不能只循环遍历值列表。
我可以尝试改善这一点吗?我想过:
添加信息
根据C.Zonnenberg的要求,有关该查询的更多信息。
填充值列表的查询基本如下:
我创建了一个IQueryable
,我为其添加了所请求物质和属性的过滤器。然后,我将相关实体中的物质,财产和价值详情包括在内。然后我执行query.ToList()
。 SQL Profiler看到的实际SQL查询看起来很复杂,涉及SubstanceId IN()和PropertyId IN(),但它执行的时间远远少于一秒。
它返回一个代理列表,如:{System.Data.Entity.DynamicProxies.SubstancePropertyValue_078F758A4FF9831024D2690C4B546F07240FAC82A1E9D95D3826A834DCD91D1E}
答案 0 :(得分:1)
我认为你最好的选择是你的第一选择。但要有效地做到这一点,我还会修改源数据(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
循环遍历所有物质中获取单元格值,您可以从并行化中受益。