c# - Ef Linq 查询超时,但相同的查询在 SSMS 上不到 1 秒

标签 c# sql-server entity-framework linq-to-entities azure-sql-database

首先,我在 SSMS 上尝试了 ARITHABORT OFF,它仍然不到 1 秒。

我使用 EntityFrameWork:6.1.3 和 Azure Sql S1 层(我会尝试使用第 3 层,如果有变化会通知您。)

我使用 EF Profiler 从 linq 获取生成的 sql。我已经查询了我共享的所有 linq,它们在 SSMS 上都不到 1 秒。

我在 AuditLog 表上有 300 万条记录。 ID 为 3 的一位客户有 170K 条记录,另一位 ID 为 35 的客户有 125 条记录。我将最小化代码。

审计日志模型:

 public class AuditLog
  {
    public long? CustomerId { get; set; }

    [ForeignKey("CustomerId")]
    public virtual CustomerSummary Customer { get; set; }

    [Required]
    [Index]
     public DateTime CreatedDate { get; set; }
  }

第一次查询:

 if (customer != null)
    {
      var customerId = customer.Id;
      var result= Dbset.Where(x => x.CustomerId == customerId).OrderByDescending(x => x.CreatedDate).Skip(0).Take(25).ToList();
    }

如果我尝试与拥有 170k 行的客户一起尝试,它会给出超时异常。如果我对有 125 条记录的客户进行尝试,没问题。

第二个查询:与第一个查询相同,我只包括客户。

if (customer != null)
   {
      var customerId = customer.Id;
      var result= Dbset.Where(x => x.CustomerId == customerId).OrderByDescending(x => x.CreatedDate).Skip(0).Take(25).Include(x => x.Customer).ToList();
    }

结果与第一个查询相反。如果我尝试与拥有 170k 行的客户一起使用,那很好。如果我尝试与有 125 条记录的客户一起尝试,它会给出超时异常。

第三个查询:与第一个查询相同,但我在 customerId 的位置匹配 long?

 if (customer != null)
    {
      long? customerId = customer.Id;
      var result= Dbset.Where(x => x.CustomerId == customerId).OrderByDescending(x => x.CreatedDate).Skip(0).Take(25).ToList();
    }

结果与第一个查询相反。如果我尝试与拥有 170k 行的客户一起使用,那很好。如果我尝试与有 125 条记录的客户一起尝试,它会给出超时异常。

第四个查询:与第二个查询相同,但我在 customerId 的位置匹配 long?

 if (customer != null)
    {
      long? customerId = customer.Id;
      var result= Dbset.Where(x => x.CustomerId == customerId).OrderByDescending(x => x.CreatedDate).Skip(0).Take(25).Include(x => x.Customer).ToList();
    }

结果与第二个查询相反。如果我尝试与拥有 170k 行的客户一起尝试,它会给出超时异常。如果我对有 125 条记录的客户进行尝试,没问题。

我真的很困惑。为什么内部连接或将匹配参数更改为 long? 会改变结果?为什么所有这些查询在 SSMS 上运行不到 1 秒并在 ef linq 上给出错误?

错误:

{System.Data.SqlClient.SqlException (0x80131904): Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding. ---> System.ComponentModel.Win32Exception (0x80004005): The wait operation timed out at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)

更新(19/04/2016):

Ivan Stoev 之后意见建议。

Have you tried (just for the sake of test) using hardcoded 3 and 35 instead of customerId variable?

我没有收到任何错误,查询速度与在 SSMS 上一样快。

更新(2016 年 4 月 20 日):真正的问题是参数嗅探。当我将参数包含或更改为可为空时,实际上我已经创建了另一个查询和另一个查询计划。我为拥有 125 条记录的客户创建了一些计划,为拥有这 4 个查询的 170k 记录的客户创建了其他计划。这就是我得到不同结果的原因。

最佳答案

您遇到的是所谓的 Parameter Sniffing Problem 的结果。 .到目前为止,我还不知道一个简单的通用解决方案,因此通常建议通过在表达式中手动绑定(bind)常量值来消除一些 SQL 查询参数来提出解决方法,例如 EntityFramework LINQ query count fails but query returns result. How to optimize LINQ query? .

对于您的场景,我建议使用以下自定义扩展方法:

public static class QueryableExtensions
{
    public static IQueryable<T> WhereEquals<T, TValue>(this IQueryable<T> source, Expression<Func<T, TValue>> selector, TValue value)
    {
        var predicate = Expression.Lambda<Func<T, bool>>(
            Expression.Equal(selector.Body, Expression.Constant(value)),
            selector.Parameters);
        return source.Where(predicate);
    }
}

然后像这样更新你的代码段

if (customer != null)
{
    var result= Dbset.WhereEquals(x => x.CustomerId.Value, customer.Id)
        .OrderByDescending(x => x.CreatedDate)
        .Skip(0).Take(25)
        .Include(x => x.Customer)
        .ToList();
}

关于c# - Ef Linq 查询超时,但相同的查询在 SSMS 上不到 1 秒,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36698792/

相关文章:

c# - 如何包含外部 (DLL) EF 实体,以便 VisualStudio 可以自动为它们创建 WebAPI Controller

entity-framework - 如何创建 Entity Framework ObjectContext?

asp.net-mvc-3 - 使用 Ninject 的 InRequestScope() 时,DbContext 在第一次请求后释放

c# - 如何使用 CancellationToken 取消任务?

c# - 在以下情况下使用指令和 SQLite 有什么问题?我得到了 ObjectDisposedException,但就在这里?

c# - 使用 AES 加密并传入查询字符串,Html.Encode 会使其工作吗?

C# - 将 TextBox 绑定(bind)到整数

sql-server - 发布配置文件中的 Visual Studio 数据库项目目标平台

sql - 从另一个表的行及其属性创建表

sql-server - SQL Server 上的“无法对聚合或子查询执行聚合函数”错误