【问题标题】:LINQ takes 40s to end query - PerformanceLINQ 需要 40 秒才能结束查询 - 性能
【发布时间】:2015-09-02 23:55:18
【问题描述】:

我正在调用本地网络之外的外部数据库,但是查询需要 40 秒才能结束..

我正在使用 edmx 拨打电话。

String Example = "Example";
var Result = EDMXEntity.Entities
    .Where(
        x => 
        (
            x.Name.ToString().ToLower().Contains(Example.ToLower())
        ))
    .Take(50)
    .ToList();

感谢 Szer 提供的当前代码:

var Result = EDMXEntity.Entities.Where(x => SqlFunctions.PatIndex(x.Name.ToString().ToLower(), Example.ToLower()) > 0).Take(50).ToList();

【问题讨论】:

  • 您的IQueryable 转换为SELECT TOP 50 * FROM [Extent1] WHERE (CAST(CHARINDEX(LOWER(@p__linq__0), LOWER(CASE WHEN ([Extent1].[Name] IS NULL) THEN N'' ELSE [Extent1].[Name] END)) AS INT)) > 0。可能 where 子句是滞后的原因
  • 您的问题是关于如何提高性能?
  • @Lightwalker 试试这个var Result = EDMXEntity.Entities.Where(x => SqlFunctions.PatIndex(x.Name.ToString().ToLower(), Example.ToLower()) > 0).Take(50).ToList();
  • @Szer 这是我的第一个猜测,但 sql server management studio 在不到一秒的时间内就完成了..
  • @Lightwalker 完成

标签: c# performance linq ef-code-first edmx


【解决方案1】:

我上面评论的迟到的答案:

问题是您正在将所有实体从数据库加载到内存并在您的机器上进行过滤。您应该在数据库引擎的帮助下过滤您的查询。

为此,您应该使用SqlFunctions,它由 LINQ SQL 提供程序映射到直接 T-SQL 代码。 在您的情况下,您可以将string.Contains() 替换为几乎相同的SqlFunctions.PatIndex(它返回int 而不是bool

像这样:

var result = EDMXEntity.Entities
   .Where(x => SqlFunctions.PatIndex(
      stringPattern: x.Name.ToString().ToLower(), 
      target:        Example.ToLower()) > 0)
   .Take(50)
   .ToList();

【讨论】:

    【解决方案2】:

    sql server management studio 不到一秒就搞定了

    这很可能是由错误的缓存查询执行计划引起的,如 hereherehere 所述。

    人们发现,对 SQL Server 运行以下命令可以解决此问题。 (有可能只有第二个命令才是真正需要的。)

    DBCC DROPCLEANBUFFERS
    DBCC FREEPROCCACHE
    

    【讨论】:

      【解决方案3】:

      字符串比较的最佳选择是使用大小写不等式,因此您不必处理转换字符串。在这种情况下,我认为名称上的 .ToString 并不是真正必要的(再说一次,我不确定它是如何存储的,所以可能需要它)。同样使用名称,您可以尝试使用相等或至少

      最后,您可以尝试将其拆分为 Queryable 对象,然后以这种方式运行查询。这样,您可以减少用于查询本身的资源数量。

      编辑

      由于不希望检查整个字符串,您可以使用 IndexOf 代替,以便不使用完整的字符串

      请参阅以下内容:

      String Example = "Example";
      var EDMXEntity = new List<String>();
      var Query = EDMXEntity.Entities.AsQueryable();
      var Result = Query
          .Where(
              x => 
              (
                  x.Name.ToString().ToLower().Contains(Example.ToLower())
              ))
          .Take(50)
          .ToList();
      

      【讨论】:

      • Dylan,这种方法的问题是查询需要完整的字符串,这意味着如果用户的名字是“John”,如果你搜索“Joh”你不会得到任何数据,这就是为什么(谢谢到@Szer)我使用了 SqlFunctions.PatIndex("%" + Example.ToLower() +"%", x.Name.ToString().ToLower()) > 0,但因为你只会在你运行查询时做 .ToList() 可能会更快。
      • @Lightwalker 我用更好的实现更新了我的代码(不只是使用完整的字符串)
      • linq 抛出错误...“LINQ to Entities 无法识别方法 'Int32 IndexOf(System.String, System.StringComparison)' 方法,并且此方法无法转换为存储表达式。 "
      • 您的编辑和我的初始代码之间的唯一区别是 .AsQueryable();
      猜你喜欢
      • 1970-01-01
      • 2017-02-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-03-25
      • 2012-12-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多