c# – 计数或跳过(1).Any()我想要找出是否有超过1条记录 – 实体框架

前端之家收集整理的这篇文章主要介绍了c# – 计数或跳过(1).Any()我想要找出是否有超过1条记录 – 实体框架前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我不知道什么时候,但是我读了一篇关于这一点的文章,这表明当使用Entity Framework时,Skip(1).Any()的使用比Count()同情更好(我可能记得错了).我看到生成的T-sql代码后,我不确定.

这是第一个选择:

  1. int userConnectionCount = _dbContext.HubConnections.Count(conn => conn.UserId == user.Id);
  2. bool isAtSingleConnection = (userConnectionCount == 1);

这将生成以下T-sql代码,这是合理的:

  1. SELECT
  2. [GroupBy1].[A1] AS [C1]
  3. FROM ( SELECT
  4. COUNT(1) AS [A1]
  5. FROM [dbo].[HubConnections] AS [Extent1]
  6. WHERE [Extent1].[UserId] = @p__linq__0
  7. ) AS [GroupBy1]

这是建议的查询的其他选项,据我所知:

  1. bool isAtSingleConnection = !_dbContext
  2. .HubConnections.OrderBy(conn => conn.Id)
  3. .Skip(1).Any(conn => conn.UserId == user.Id);

以下是用于上述LINQ查询生成的T-sql

  1. SELECT
  2. CASE WHEN ( EXISTS (SELECT
  3. 1 AS [C1]
  4. FROM ( SELECT [Extent1].[Id] AS [Id],[Extent1].[UserId] AS [UserId]
  5. FROM ( SELECT [Extent1].[Id] AS [Id],[Extent1].[UserId] AS [UserId],row_number() OVER (ORDER BY [Extent1].[Id] ASC) AS [row_number]
  6. FROM [dbo].[HubConnections] AS [Extent1]
  7. ) AS [Extent1]
  8. WHERE [Extent1].[row_number] > 1
  9. ) AS [Skip1]
  10. WHERE [Skip1].[UserId] = @p__linq__0
  11. )) THEN cast(1 as bit) WHEN ( NOT EXISTS (SELECT
  12. 1 AS [C1]
  13. FROM ( SELECT [Extent2].[Id] AS [Id],[Extent2].[UserId] AS [UserId]
  14. FROM ( SELECT [Extent2].[Id] AS [Id],[Extent2].[UserId] AS [UserId],row_number() OVER (ORDER BY [Extent2].[Id] ASC) AS [row_number]
  15. FROM [dbo].[HubConnections] AS [Extent2]
  16. ) AS [Extent2]
  17. WHERE [Extent2].[row_number] > 1
  18. ) AS [Skip2]
  19. WHERE [Skip2].[UserId] = @p__linq__0
  20. )) THEN cast(0 as bit) END AS [C1]
  21. FROM ( SELECT 1 AS X ) AS [SingleRowTable1];

哪一个是正确的方法?这两者之间有很大的性能差异吗?

解决方法

查询性能取决于很多事情,如存在的索引,实际数据,关于数据存在的统计信息的陈旧程度等等.SQL查询计划优化程序会查看这些不同的度量标准来提供有效的查询计划.所以,任何简单的回答说,查询1总是比查询2更好,反之亦然.

那就是说,我下面的答案试图解释文章的立场,并且Skip(1).Any()可能比做Count()>更好(稍微)第二个查询虽然尺寸更大,大部分都是不可读的,但可以用高效的方式解释.再次,这取决于前面提到的事情.这个想法是数据库必须研究的行数,以计算出结果在Count()的情况下更多.在计数情况下,假设所需的索引在那里(Id上的聚簇索引使OrderBy在第二种情况下有效),db必须经过计数行数.在第二种情况下,最多需要经过两行才能得出答案.

让我们分析更加科学,看看我的上述理论是否有理由.为此,我正在创建一个客户的虚拟数据库.客户类型看起来像这样,

  1. public class Customer
  2. {
  3. public int ID { get; set; }
  4. public string Name { get; set; }
  5. public int Age { get; set; }
  6. }

我正在使用这个代码为大约100K个随机行播放数据库(我真的要证明这一点)

  1. for (int j = 0; j < 100; j++)
  2. {
  3. using (CustomersContext db = new CustomersContext())
  4. {
  5. Random r = new Random();
  6. for (int i = 0; i < 1000; i++)
  7. {
  8. Customer c = new Customer
  9. {
  10. Name = Guid.NewGuid().ToString(),Age = r.Next(0,100)
  11. };
  12. db.Customers.Add(c);
  13. }
  14. db.SaveChanges();
  15. }
  16. }

示例代码here.

现在,我要使用的查询如下,

  1. db.Customers.Where(c => c.Age == 26).Count() > 1; // scenario 1
  2.  
  3. db.Customers.Where(c => c.Age == 26).OrderBy(c => c.ID).Skip(1).Any() // scenario 2

我已经启动sql分析器来捕获查询计划.捕获的计划如下,

情景1:

查看上述图像中情景1的估计成本和实际行数.

情景2:

查看以下图像中场景2的估计成本和实际行数.

根据最初的猜测,在Skip和任何情况下,与Count案相比,估计成本和行数都较少.

结论:

除此之外,除了许多其他人之前的评论之外,所有这些分析都不是您在代码中应该尝试的那种性能优化.像这样的事情很少受到伤害的可读性(我会说不存在)perf的好处.我只是做了这个分析的乐趣,永远不会使用它作为选择场景2的基础.我将测量并看看是否做一个Count()实际上是伤害更改代码使用Skip().Any().

猜你在找的C#相关文章