c# – 计数或跳过(1).Any()我想要找出是否有超过1条记录 – 实体
我不知道什么时候,但是我读了一篇关于这一点的文章,这表明当使用Entity Framework时,Skip(1).Any()的使用比Count()同情更好(我可能记得错了).我看到生成的T-SQL代码后,我不确定.
这是第一个选择: int userConnectionCount = _dbContext.HubConnections.Count(conn => conn.UserId == user.Id); bool isAtSingleConnection = (userConnectionCount == 1); 这将生成以下T-SQL代码,这是合理的: SELECT [GroupBy1].[A1] AS [C1] FROM ( SELECT COUNT(1) AS [A1] FROM [dbo].[HubConnections] AS [Extent1] WHERE [Extent1].[UserId] = @p__linq__0 ) AS [GroupBy1] 这是建议的查询的其他选项,据我所知: bool isAtSingleConnection = !_dbContext .HubConnections.OrderBy(conn => conn.Id) .Skip(1).Any(conn => conn.UserId == user.Id); 以下是用于上述LINQ查询的生成的T-SQL: SELECT CASE WHEN ( EXISTS (SELECT 1 AS [C1] FROM ( SELECT [Extent1].[Id] AS [Id],[Extent1].[UserId] AS [UserId] FROM ( SELECT [Extent1].[Id] AS [Id],[Extent1].[UserId] AS [UserId],row_number() OVER (ORDER BY [Extent1].[Id] ASC) AS [row_number] FROM [dbo].[HubConnections] AS [Extent1] ) AS [Extent1] WHERE [Extent1].[row_number] > 1 ) AS [Skip1] WHERE [Skip1].[UserId] = @p__linq__0 )) THEN cast(1 as bit) WHEN ( NOT EXISTS (SELECT 1 AS [C1] FROM ( SELECT [Extent2].[Id] AS [Id],[Extent2].[UserId] AS [UserId] FROM ( SELECT [Extent2].[Id] AS [Id],[Extent2].[UserId] AS [UserId],row_number() OVER (ORDER BY [Extent2].[Id] ASC) AS [row_number] FROM [dbo].[HubConnections] AS [Extent2] ) AS [Extent2] WHERE [Extent2].[row_number] > 1 ) AS [Skip2] WHERE [Skip2].[UserId] = @p__linq__0 )) THEN cast(0 as bit) END AS [C1] FROM ( SELECT 1 AS X ) AS [SingleRowTable1]; 哪一个是正确的方法?这两者之间有很大的性能差异吗? 解决方法
查询性能取决于很多事情,如存在的索引,实际数据,关于数据存在的统计信息的陈旧程度等等.SQL查询计划优化程序会查看这些不同的度量标准来提供有效的查询计划.所以,任何简单的回答说,查询1总是比查询2更好,反之亦然.
那就是说,我下面的答案试图解释文章的立场,并且Skip(1).Any()可能比做Count()>更好(稍微)第二个查询虽然尺寸更大,大部分都是不可读的,但可以用高效的方式解释.再次,这取决于前面提到的事情.这个想法是数据库必须研究的行数,以计算出结果在Count()的情况下更多.在计数情况下,假设所需的索引在那里(Id上的聚簇索引使OrderBy在第二种情况下有效),db必须经过计数行数.在第二种情况下,最多需要经过两行才能得出答案. 让我们分析更加科学,看看我的上述理论是否有理由.为此,我正在创建一个客户的虚拟数据库.客户类型看起来像这样, public class Customer { public int ID { get; set; } public string Name { get; set; } public int Age { get; set; } } 我正在使用这个代码为大约100K个随机行播放数据库(我真的要证明这一点) for (int j = 0; j < 100; j++) { using (CustomersContext db = new CustomersContext()) { Random r = new Random(); for (int i = 0; i < 1000; i++) { Customer c = new Customer { Name = Guid.NewGuid().ToString(),Age = r.Next(0,100) }; db.Customers.Add(c); } db.SaveChanges(); } } 示例代码here. 现在,我要使用的查询如下, db.Customers.Where(c => c.Age == 26).Count() > 1; // scenario 1 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(). (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |