Ef Linq查询超时,但SSMS上的查询不到1秒

Erk*_*rel 7 c# sql-server linq-to-entities entity-framework azure-sql-database

首先我尝试ARITHABORT OFF了SSMS,但仍然不到1秒.

我使用EntityFrameWork:6.1.3和Azure Sql S1层(我将尝试使用第3层,让你知道是否有变化.)

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

我在AuditLog Table上有300万个recods.ID 3的一个客户有170K记录,ID 35的另一个客户有125个记录.我会尽量减少代码.

AuditLog模型:

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

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

    [Required]
    [Index]
     public DateTime CreatedDate { get; set; }
  }
Run Code Online (Sandbox Code Playgroud)

第一个查询:

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

如果我尝试拥有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();
    }
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

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

 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();
    }
Run Code Online (Sandbox Code Playgroud)

结果与第二个查询相反.如果我尝试拥有170k行的客户,它会给出超时的例外.如果我尝试拥有125条记录的客户,那很好.

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

错误:

{System.Data.SqlClient.SqlException(0x80131904):超时已过期.操作完成之前经过的超时时间或服务器没有响应.---> System.ComponentModel.Win32Exception(0x80004005):等待操作在System.Data.SqlClient.SqlConnection.OnError超时(SqlException异常,Boolean breakConnection,Action`1 wrapCloseInAction)

更新(2016年4月19日):

Ivan Stoev就意见提出建议之后.

您是否尝试过(仅仅为了测试)使用硬编码的3和35而不是customerId变量?

我没有收到任何错误,查询速度最快,就像在SSMS上一样.

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

Iva*_*oev 5

您遇到的是所谓的“ 参数嗅探问题”的结果。到目前为止,我还不知道一个简单的通用解决方案,因此通常建议一种解决方法,即通过在表达式内部手动绑定常量值来消除一些SQL查询参数,例如在EntityFramework LINQ中查询失败,但是查询返回结果。如何优化LINQ查询?

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

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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();
}
Run Code Online (Sandbox Code Playgroud)