【问题标题】:Linq and .Count big databaseLinq 和 .Count 大数据库
【发布时间】:2017-05-07 10:27:16
【问题描述】:

我创建了一个从大型 Mysql 数据库中获取数据的 asp mvc 项目 ~ 500000。

我使用单独的列过滤器将数据表添加到我的前端,其中仅显示 10 个条目。

data = dc.books.OrderBy(x => x.id).Where(x =>
        (market_id == 0 || x.market_id == market_id)
        && (name == null || x.name != null && (x.name.Contains(name)))
        && (author == null || x.author != null && (x.author.Contains(author)))
    ).Skip(param.Start).Take(10).ToList();

工作又快又好。

当我尝试在过滤器之后添加计数以进行合并时。 Not work server Mysql Timeout 错误或工作很慢

count = db.books.Count(x =>
                    (market_id == 0 || x.market_id != 0 && x.market_id == market_id)
                    && (name == null || x.name != null && (x.name.StartsWith(name)))

为什么计数不工作还是那么慢?

所有代码我的控制器here

【问题讨论】:

  • Sql Server 在计数方面往往非常快(也包括谓词)。无论计数是否快速,它都可能在数据库引擎中根深蒂固。我不了解 MySql,但我认为您缺少一些重要的索引。

标签: c# mysql linq


【解决方案1】:

你最好这样做:

var query = db.books.AsQueryable();

if (market_id!=0)
  query = query.Where(x=>x.market_id==market_id);

if (name!=null)
  query = query.Where(x=>x.name.StartsWith(name));

count = query.Count();
data = query
  .OrderBy(x=>x.id)
  .Skip(param.Start)
  .Take(10)
  .ToList();

并非所有 LINQ 提供程序都非常擅长优化过滤器,并将它们传递给数据库。许多数据库会为这些类型的查询生成一个糟糕的查询计划,并生成最坏情况的查询计划并将其重新用于所有看起来像这样的查询,这将错过使用索引的可能性,如果你通常会这样做使用上面的代码。

在很多情况下,您可能还想限制计数,因此您可以这样做:

count = query.Take(1001).Count();

然后如果 count == 1001 则使用消息“超过 1000 个结果”。

【讨论】:

    【解决方案2】:

    这一切都取决于数据库如何工作以及最终生成什么样的 SQL。 StartsWith 被转换为通配符搜索,这可能比简单的查询要慢。您可以尝试放入有助于您尝试优化的特定查询的索引,并且您可以查看生成的 SQL 以检查它是否与您期望的一样好(有时它会生成奇怪的 SQL,但这看起来像足够简单的查询,所以我不会太担心)。如果您添加括号来分隔 OR 表达式的各个部分,您可能还想检查生成的 SQL 是否有任何差异,例如 name == null || (x.name != null && (x.name.StartsWith(name)))

    【讨论】:

      猜你喜欢
      • 2011-04-30
      • 2012-06-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-05-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多