1

我遇到了一个同事的代码,并认为它可能效率低下

bool any = (from c in listDeviceMaxDate
             where c.DeviceKey == m_deviceList[i].deviceKey
             select c).Any();

if (!any)
{
    latestDate = (DateTime)System.Data.SqlTypes.SqlDateTime.MinValue;
}
else
{
    // from the list we have get the lastest max date from the flow table
    DeviceDateTimeItem temp = (from c in listDeviceMaxDate
                                where c.DeviceKey == m_deviceList[i].deviceKey
                                select c).First();

    latestDate = Convert.ToDateTime(temp.dateTimeMax);
}

我的第一直觉是存储 linq 查询,然后根据需要引用它,但后来我意识到First()操作员可能会阻止 linq 实际获取不受约束的查询会执行的所有行。

我最初是如何考虑重构代码的:

var deviceList = from c in listDeviceMaxDate
                            where c.DeviceKey == m_deviceList[i].deviceKey
                            select c;

if (!deviceList.Any())
{
    latestDate = (DateTime)System.Data.SqlTypes.SqlDateTime.MinValue;
}
else
{
    // from the list we have get the lastest max date from the flow table
    DeviceDateTimeItem temp = deviceList.First();

    latestDate = Convert.ToDateTime(temp.dateTimeMax);
}

我的问题是First()对第二个 linq 查询的调用是否会阻止它返回所有结果,因此,以原始方式执行它实际上是否更快?

4

1 回答 1

3

它实际上取决于它是什么 LINQ 实现。如果它是 LINQ-to-Objects(即IEnumerable<T>),那么它基本上只是枚举数据,无论它是什么,如果有则返回第一项。First()道德上的等价物是:

foreach(var val in sequence) return val;
throw OopsNoData();

并且Any()应该很好地比较:

foreach(var val in sequence) return true;
return false;

(它可能在实际实现中使用原始迭代器,而不是foreach

然而!如果它是 LINQ-to-anything-else,那么所有的赌注都没有了。LINQ 查询(尤其是 LINQ 查询IQueryable<T>)被设计为可组合的——例如,我希望 LINQ-to-SQL 能够构成First()TSQLselect TOP 1 ...查询,并且对于大多数其他数据库后端也是如此。所以是的,告诉它你只想要一排应该会有所帮助。然而!我也希望.Any()做一些非常相似的事情,所以(理论上)不应该有很大的不同。在一个完美的世界里,它甚至可能用exists(...)在 TSQL 中,但这个世界远非完美。

找出方法:附上一个sql tracer,看看最终的TSQL是什么。


做到这一点的最终方法更简单:

var obj = someQuery.FirstOrDefault();
if(obj == null) {
   // no match
} else {
   // do something with "obj"
}
于 2012-07-25T11:14:17.677 回答