试图优化if / else条件减慢程序

时间:2013-06-19 14:15:54

标签: c# optimization compiler-construction

我目前正在尝试借助VS-Profiling工具优化.net应用程序。

一个经常调用的函数包含以下代码:

if (someObjectContext.someObjectSet.Where(i => i.PNT_ATT_ID == tmp_ATT_ID).OrderByDescending(i => i.Position).Select(i => i.Position).Count() == 0)
{
    lastPosition = 0;
}
else
{
    lastPosition = someObjectContext.someObjectSet.Where(i => i.PNT_ATT_ID == tmp_ATT_ID).OrderByDescending(i => i.Position).Select(i => i.Position).Cast<int>().First();
}

我改变了这样的事情:

var relevantEntities = someObjectContext.someObjectSet.Where(i => i.PNT_ATT_ID == tmp_ATT_ID).OrderByDescending(i => i.Position).Select(i => i.Position);
if (relevantEntities.Count() == 0)
{
    lastPosition = 0;
}
else
{
    lastPosition = relevantEntities.Cast<int>().First();
}

我希望这个改变会加快方法的速度,因为我不确定编译器是否会注意到查询已完成两次并缓存结果。

令我惊讶的是,该方法的执行时间(墨水样本的数量)没有减少,但甚至增加了9%(根据剖析器)

有人可以解释为什么会这样吗?

2 个答案:

答案 0 :(得分:3)

如果没有符合条件的实体,您可以使用Max()获取最大位置而不是排序和获取第一项,并DefaultIfEmpty()提供默认值(int为零)。顺便说一句,如果序列为空,你可以提供自定义默认值。

lastPosition = someObjectContext.someObjectSet
                                .Where(i => i.PNT_ATT_ID == tmp_ATT_ID)
                                .Select(i => i.Position)
                                .Cast<int>()
                                .DefaultIfEmpty() 
                                .Max();

因此,您将避免执行两个查询 - 一个用于定义是否有任何位置,另一个用于获取最新位置。

答案 1 :(得分:3)

  

我希望更改会加快方法的速度,因为我不确定编译器是否会注意到查询已完成两次并缓存结果。

不会。事实上它不能。数据库可能不会为两个查询返回相同的结果。在第一次查询之后和第二次查询之前添加或删除结果是完全可能的。 (使这些代码不仅低效,但如果发生这种情况可能会破坏。)因为你完全有可能想要执行两个查询,因为知道结果会有所不同,所以结果很重要 not 的查询可以重复使用。

这里重点是延迟执行的想法。 relevantEntities 不是查询的结果,而是查询本身。直到IQueryable被迭代(通过诸如CountFirstforeach循环等方法),才会查询数据库,并且每次都要查询你迭代查询它将对数据库执行另一个查询。

在你的情况下,你可以这样做:

var lastPosition = someObjectContext.someObjectSet
    .Where(i => i.PNT_ATT_ID == tmp_ATT_ID)
    .OrderByDescending(i => i.Position)
    .Select(i => i.Position)
    .Cast<int>()
    .FirstOrDefault();

这利用了int的默认值为0的事实,这是您在之前不匹配的情况下将值设置为的内容。

请注意,这是一个功能与您相同的查询,它只是避免执行两次。更好的查询是由lazyberezovsky建议的,您利用Max而不是排序并获取第一个查询。如果该列上有索引就没有太大差别,但如果,索引排序会更加昂贵。