【问题标题】:Linq query taking a long time to query a table with 6000 recordsLinq 查询需要很长时间才能查询一个有 6000 条记录的表
【发布时间】:2014-01-16 20:14:00
【问题描述】:

我在尝试编写查询时遇到问题。我有一张表,里面有大约 6000 条记录。

目前在我的开发机器上运行大约需要 15 秒。一台运行 vs2012 和 sql2012 的 32gb ram 四核 win8 机器。所以它不是我的机器而是我的错误代码。

    public IEnumerable<Customer> GetByStoreIdAndContainingName(Guid storeId, string containing)
    {
        using (var context = new Entities())
        {
            var store = context.Stores.FirstOrDefault(b => b.StoreId == storeId);
            if (store == null) return null;
            var business = store.Business;
            var consumers = new List<Consumer>();


            consumers =
                business.ConsumerIdentities.Select(ci => ci.Consumer)
                        .Distinct()
                        .Where(x => x.FirstName.ToLower().Contains(containing.ToLower()))
                        .ToList();

数据库表的布局是

商业

企业ID
名称
等等

StoreId

商店ID
店名
业务编号

消费者

消费者ID
名字
姓氏

消费者身份

企业ID
消费者身份类型
消费者身份价值

谁能看到我做错了什么明显的事情,需要很长时间才能返回查询结果?

开启 SQL Profiler 很可怕。第一个查询是从 ConsumerIdentity 表中选择与企业 ID 匹配的所有内容。太棒了,然后得到商务表。

然后似乎对每条记录都进行了调用,例如

exec sp_executesql N'SELECT 
[Extent1].[ConsumerId] AS [ConsumerId], 
[Extent1].[UserID] AS [UserID], 
[Extent1].[FirstName] AS [FirstName], 
[Extent1].[LastName] AS [LastName], 
[Extent1].[IsMale] AS [IsMale], 
[Extent1].[DateOfBirth] AS [DateOfBirth], 
FROM [dbo].[Consumer] AS [Extent1]
WHERE [Extent1].[ConsumerId] = @EntityKeyValue1',N'@EntityKeyValue1     uniqueidentifier',@EntityKeyValue1='952ED7B8-2123-49E2-BAE3-69FBD713BACB'

所以看起来我的 where 语句没有被应用

【问题讨论】:

  • 我将首先查看实际的 sql 查询及其在 microsoft sql server management studio 中的执行计划(您可以使用 sql profiler 跟踪查询)。
  • 如果还没有,请尝试在 Release(没有任何调试标志)配置中运行
  • 或使用此调试可视化工具:visualstudiogallery.msdn.microsoft.com/…
  • 你在这些表上有什么索引?
  • 目前我的表上没有任何索引。我现在会尝试添加这些

标签: c# linq entity-framework linq-to-entities


【解决方案1】:

我将从 Customer 开始(如果属性存在),因为这首先会保存 Distinct,它应该在一个 SQL 语句中完成所有操作:

from c in Customer
where c.FirstName.ToLower().Contains(containing.ToLower())
      && c.ConsumerIdentity.Business.StoreId == storeId
select c

这不会删除c.FirstName.ToLower() 上的where。这样的构造总是会影响性能,因为它们不是sargable(它们消除了任何索引)。 EF 目前没有工具来进行不区分大小写的搜索(它不接受带有IEqualityComparerContains 重载),因此从技术上讲,您无法避免这种情况。但很可能数据库排序规则不区分大小写,因此x.FirstName.Contains(containing.ToLower() 可能会给出相同的结果,with 索引。

【讨论】:

  • 我对此表示赞同,因为从最终实体对象开始的想法(大多数情况下)是个好主意。
【解决方案2】:

我只看到一件可以改进的地方:

  • Where 之后使用DistinctDistinct 是 O(n log n) Where in O(n))

        consumers =
            business.ConsumerIdentities.Select(ci => ci.Consumer)
                    .Where(x => x.FirstName.ToLower().Contains(containing.ToLower()))
                    .Distinct()
                    .ToList();
    

但我怀疑您的性能问题来自 LINQ 查询(无论如何,6000 条记录应该非常快)。

【讨论】:

    【解决方案3】:

    在 Where 之后执行 Select 会有帮助吗?

            consumers =
                business.ConsumerIdentities
                        .Where(x => x.FirstName.ToLower().Contains(containing.ToLower()))
                        .Distinct()
                        .Select(ci => ci.Consumer)
                        .ToList();
    

    【讨论】:

    • Consumer 包含 FirstName 所以哪里会失败
    【解决方案4】:

    有几种优化方法可能会减少处理时间(其他人告诉过),但是您查询的任何方式都是在具有 6000 条记录的数据库上执行搜索过程。 但是对于 6000 条记录,它应该比 15 秒更快。

    这可能是因为您的内存缓存。 我建议清除您的 VS 和系统缓存,然后重试。 (您可以使用 C-Cleaner 应用程序进行系统缓存)

    您也可以在 ADO 中使用异步启动。 它对减少处理时间有很大的作用。 (您可以使用支持异步的 IDataReadables 和 IDataReaders 来完成)

    【讨论】:

      猜你喜欢
      • 2016-04-22
      • 2018-07-06
      • 1970-01-01
      • 2021-12-25
      • 2016-06-17
      • 2021-06-15
      • 2011-01-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多