【问题标题】:Linq, is select().SingleorDefault() a bad idea?Linq, select().SingleorDefault() 是个坏主意吗?
【发布时间】:2012-01-31 05:40:43
【问题描述】:
 var queueitem = context.CrawlerQueues.
                 Select(cq => new{cq.Guid,cq.Result}).
                 SingleOrDefault(cq => cq.Guid == guid);

上面是个坏主意,它是先选择所有数据库行然后找到那一行,还是智能地查看其使用的上下文并仅获取一行。

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

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

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

【问题讨论】:

    标签: c# asp.net linq


    【解决方案1】:

    "它会先选择所有数据库行然后找到那个"

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

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

    想一想:查询如何知道这一行是数据集中匹配的only行?它将不得不尝试找到下一行。如果在数据集中只有数百万行匹配,Single() 可能必须遍历所有这些数百万行来证明当前匹配是唯一的匹配。

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

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

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

    【讨论】:

    • 谢谢。我一直在使用 firstordefault 但在提出问题时我不知何故忘记了。
    • 我也打算推荐 FirstOrDefault()。
    【解决方案2】:

    我很确定这不会在过滤之前返回整个数据库,因为在“评估”语句执行之前不会执行查询,这是该查询中的 SingleOrDefault()。

    如果你有

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

    那么这将在过滤之前评估ToList(),但目前的查询很好。

    如果您不确定评估路径或从您的 LINQ 语句生成的 SQL,LINQPad 是一个非常好的工具,它使使用 Linq、Linq2Sql、EF 变得非常容易。

    【讨论】:

      【解决方案3】:

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

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

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

      【讨论】:

        【解决方案4】:

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

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

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

        【讨论】:

          猜你喜欢
          • 2011-05-17
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2010-11-09
          • 1970-01-01
          • 2010-09-28
          • 2014-05-21
          相关资源
          最近更新 更多