Linq,是select()。SingleorDefault()一个坏主意?

时间:2012-01-31 05:40:43

标签: c# asp.net linq

 var queueitem = context.CrawlerQueues.
                 Select(cq => new{cq.Guid,cq.Result}).
                 SingleOrDefault(cq => cq.Guid == guid);

这是一个坏主意,它会先选择所有数据库行,然后找到一个或者它是否聪明,并查看其中使用的上下文,只获取一行。

这样做的原因是我想只返回Guid和Result coloums。

return Newtonsoft.Json.JsonConvert.SerializeObject(queueitem, Formatting.Indented);

如何在不监控网络流量或对数据库发出的请求的情况下找到答案?

4 个答案:

答案 0 :(得分:14)

“它会首先选择所有数据库行,然后找到一个”

从技术上讲,不,.Select后跟.SingleOrDefault的组合不会那样做。 Select()设置查询的参数,但它实际上不会获取任何数据。 LINQ的延迟执行不会获取任何行,直到实际上必须产生数据结果。您可以一起编写多个查询(.Select(...)。选择(..)等)并且在执行返回数据的操作(例如First()或.ToList())之前,实际上不会提取任何行。

但是,使用Single()可能会导致扫描整个数据集,以证明一个匹配的行是唯一匹配的行。

考虑一下:查询如何知道一行是匹配的数据集中的 only 行?它必须尝试找到下一行。如果实际上只有一行匹配数据集中的数百万行,则Single()可能必须遍历所有这些数百万行,以证明当前匹配是唯一匹配。

如果您的数据集是SQL,并且您的数据以允许查询优化的方式编制索引,则Single()可能不会那么糟糕。但是,如果您的SQL数据没有以对此查询有帮助的方式编制索引,则Single()可能会为SQL服务器创建大量工作。

如果您的程序逻辑确实需要知道返回的行是整个数据集中唯一的行,则单个()是合适的。但是,还有其他方法可以保证唯一性。如果您可以在数据上设置与LINQ条件匹配的主键,那么只有一个匹配行可以存在/可以添加到数据库中,因此您不需要Single()。 (具有讽刺意味的是,在这种情况下,Single()的性能也会非常快,因为主键索引可用于优化查询)

如果您只想要匹配条件的第一行,请使用First()而不是Single()。 First()只需要扫描数据行,直到找到第一个匹配项。它不必继续扫描行来证明第一个匹配是唯一匹配,如Single()。

答案 1 :(得分:3)

我很确定这不会在过滤之前返回整个数据库,因为在执行'evaluate'语句之后才会执行查询,这是此查询中的SingleOrDefault()。

如果你有

context.CrawlerQueues.ToList().Select(cq => new{cq.Guid,cq.Result}).SingleOrDefault(cq => cq.Guid == guid);

然后这将在过滤之前评估ToList(),但是查询原样很好。

如果您不确定评估路径或LINQ语句中生成的SQL,LINQPad是一个非常好的工具,可以很容易地使用Linq,Linq2Sql,EF。

答案 2 :(得分:2)

SingleOrDefault - 返回序列的唯一元素,如果序列为空则返回默认值; 如果序列中有多个元素,则此方法会抛出异常。

FirstOrDefault - 返回序列的第一个元素,如果序列不包含元素,则返回默认值。

从语义上讲,您需要FirstorDefault,因为您的问题提到了多行返回。

答案 3 :(得分:1)

实际执行的查询实际上取决于Linq提供程序,但是,Linq提供程序将不会在最后一刻进行评估,因此在执行查询之前它将知道上下文(SingleOrDefault)。一个好人不会取得任何不必要的东西。

一个好的Linq实现实际上会获取2行,因为SingleOrDefault会处理3个案例;

  • 没有返回行 - >返回默认值
  • 返回一行 - >返回该行
  • 返回多行 - >抛出异常(Sequence包含多个元素)