entity framework核心数量没有最佳性能

我需要通过某个filter获取记录数量。

从理论上讲这条指令:

_dbContext.People.Count (w => w.Type == 1); 

它应该生成SQL,如:

 Select count (*) from People Where Type = 1 

但是,生成的SQL是:

 Select Id, Name, Type, DateCreated, DateLastUpdate, Address from People Where Type = 1 

生成的查询在具有许多记录的数据库中运行需要更长的时间。

我需要生成第一个查询。

如果我这样做:

 _dbContext.People.Count (); 

entity framework生成以下查询:

 Select count (*) from People 

..运行得非常快。

如何生成第二个查询将搜索条件传递给计数?

这里没什么可回答的。 如果您的ORM工具没有从简单的LINQ查询生成预期的SQL查询,那么您无法通过重写查询来让它执行此操作(并且您不应该首先执行此操作)。

EF Core 在LINQ查询中具有混合客户端/数据库评估的概念,允许他们发布具有不完整/非常低效的查询处理的EF Core版本,就像您的情况一样。

不包含在EF Core中的function摘录(注意单词not )和路线图 :

改进了转换以使更多查询成功执行,在数据库(而不是内存)中评估更多逻辑。

不久,他们正在计划改进查询处理,但我们不知道何时会发生这种程度和程度(记住混合模式允许他们考虑查询“工作”)。

那有什么选择呢?

  • 首先,远离EF Core,直到它变得非常有用。 回到EF6,没有这样的问题。
  • 如果您无法使用EF6,请使用最新的EF Core版本保持更新。

例如,在v1.0.1和v1.1.0中,您查询生成了预期的SQL(已测试),因此您可以简单地升级并且具体问题将消失。

但请注意,随着改进,新版本会引入错误/回归(正如您在此处看到的, EFCore为简单的LEFT OUTER连接返回了太多列 ),因此请自行承担风险(并再次考虑第一个选项,即哪一个适合你 🙂

试试这个

 (from x in _dbContext.People where x.Type == 1 select x).Count(); 

或者你可以做它的异步版本,如:

 await (from x in _dbContext.People where x.Type == 1 select x).CountAsync(); 

如果那些不适合你,那么你至少可以通过这样做来提高查询效率:

 (from x in _dbContext.People where x.Type == 1 select x.Id).Count(); 

要么

 await (from x in _dbContext.People where x.Type == 1 select x.Id).CountAsync(); 

如果要优化性能并且当前的EF提供程序(尚未)能够生成所需的查询,则始终可以依赖原始SQL 。

显然,这是一个权衡,因为您使用EF来避免直接编写SQL,但如果您要执行的查询无法使用LINQ表示,或者如果使用LINQ查询导致使用原始SQL,则使用原始SQL会很有用将低效的SQL发送到数据库。

示例原始SQL查询将如下所示:

 var results = _context.People.FromSql("SELECT Id, Name, Type, " + "FROM People " + "WHERE Type = @p0", 1); 

据我所知,传递给FromSql扩展方法的原始SQL查询当前要求您返回模型类型,即可能尚不支持返回标量结果。

但是,您可以始终返回到纯ADO.NET查询:

 using (var connection = _context.Database.GetDbConnection()) { connection.Open(); using (var command = connection.CreateCommand()) { command.CommandText = "SELECT COUNT(*) FROM People WHERE Type = 1"; var result = command.ExecuteScalar().ToString(); } } 

尝试更快地使用此lambda表达式执行查询。

 _dbContext.People.select(x=> x.id).Count(); 

这会得到你想要的:

 _dbContext.People.Where(w => w.Type == 1).Count(); 

似乎Entity Framework Core的早期版本之一存在一些问题。 不幸的是,你没有指定确切的版本,所以我无法深入了解EF源代码,以确定究竟出了什么问题。

为了测试这种情况,我安装了最新的EF Core软件包并设法获得正确的结果。

这是我的测试程序: 源代码

以下是SQL Server Profiler捕获的SQL生成内容: 在此处输入图像描述

正如您所看到的,它符合所有期望。

以下是packages.config文件的摘录:

 ...  ... 

因此,在您的情况下,唯一的解决方案是在编写本文时更新到最新的1.1.0版程序包。

我在这里使用EFCore 1.1。

如果EFCore无法将整个Where子句转换为SQL,则会发生这种情况。 这可以像DateTime.Now那样简单,甚至可能没有想到。

以下语句导致SQL查询在加载整个表后会令人惊讶地运行SELECT * ,然后运行C# .Count()

  int sentCount = ctx.ScheduledEmail.Where(x => x.template == template && x.SendConfirmedDate > DateTime.Now.AddDays(-7)).Count(); 

但是这个查询将运行SQL SELECT COUNT(*)正如您期望/希望的那样:

  DateTime earliestDate = DateTime.Now.AddDays(-7); int sentCount = ctx.ScheduledEmail.Where(x => x.template == template && x.SendConfirmedDate > earliestDate).Count(); 

疯狂但真实。 幸运的是,这也有效:

  DateTime now = DateTime.Now; int sentCount = ctx.ScheduledEmail.Where(x => x.template == template && x.SendConfirmedDate > now.AddDays(-7)).Count(); 

我以前使用搜索查询计算行数是

 _dbContext.People.Where(w => w.Type == 1).Count(); 

这也可以通过以下方式实现

 List people = new List(); people = _dbContext.People.Where(w => w.Type == 1); int count = people.Count(); 

这样,如果您需要它,您也可以获得人员列表。