实体框架 DbContext 过滤的计数查询使用变量非常慢

Posted

技术标签:

【中文标题】实体框架 DbContext 过滤的计数查询使用变量非常慢【英文标题】:Entity Framework DbContext filtered query for count is extremely slow using a variable 【发布时间】:2020-02-07 17:08:25 【问题描述】:

使用 ADO.NET 实体数据模型,我在下面针对包含 1800 条记录的表构建了两个查询,其中包含 30 多个字段,产生了惊人的结果。

// Executes slowly, over 6000 ms
int count = context.viewCustomers.AsNoTracking()
                   .Where(c => c.Cust_ID == _custID).Count();

// Executes instantly, under 20 ms
int count = context.viewCustomers.AsNoTracking()
                   .Where(c => c.Cust_ID == 625).Count();

我从数据库日志中看到,Entity Framework 提供的查询几乎相同,只是过滤器部分使用了一个参数。将此查询复制到 SSMS 并在其中声明和设置此参数会导致近乎即时的查询,因此它似乎不在数据库端。

有没有人遇到过可以解释发生了什么的情况?我受制于第三方控件,该控件将此命令添加到查询中以尝试限制返回的行数,因此必须获得计数。这用于多个查询,因此需要通用解决方案。不幸的是,它并没有像宣传的那样工作,它似乎只使查询花费的时间是我将整个视图加载到内存中的 5-10 倍。然而,当不使用过滤器时,它就像做梦一样。

这些组件的使用包括源代码,因此我可以更改此行为,但需要考虑可以使用哪些方法来提供可重用的解决方案。

【问题讨论】:

我猜你的表在Cust_ID 列上没有Index。也许您可以检查并再次确认。 【参考方案1】:

您没有提及模型的设计细节,但如果您只想根据条件计算记录,那么可以通过仅基于一列计算结果集来优化。例如,

    int count = context.viewCustomers.AsNoTracking().Where(c => c.Cust_ID == _custID).Count();

如果您设计有 10 列,并且根据上述语句假设返回了 100 条记录,那么针对每个记录结果集包含 10 列未使用的数据。

您可以通过仅计算基于单列的结果集来优化这一点。

   int count = context.viewCustomers.AsNoTracking().Where(c => c.Cust_ID == _custID).Select(x=>new x.column).Count();

可以使用其他优化方法,例如使用 count CountAsync 的异步变体。

【讨论】:

以上是关于实体框架 DbContext 过滤的计数查询使用变量非常慢的主要内容,如果未能解决你的问题,请参考以下文章

将 POCO/实体添加到 DbContext 以进行自定义查询/过程,而无需先在实体框架代码中创建表

在Code第一实体框架中将DbContext转换为Datatable

实体框架查询刚刚添加但未保存的值

忽略连接实体的全局查询过滤器

如何从实体框架 DbContext 收集当前的 SQL Server 会话 ID?

为啥在使用实体框架时要重新启动 DbContext?