【问题标题】:Slow linq enumeration慢速 linq 枚举
【发布时间】:2009-09-22 19:45:14
【问题描述】:

我一直致力于生成各种图表的 Silverlight 应用程序。它需要一些数字运算以及从数据库中获取大量数据。

对于我的数据库通信,我创建了一个使用 Linq2SQL 的 Web 服务。为了克服我的 Web 服务崩溃的问题,我将数据分块,导致有时需要 3 次 Web 服务调用才能全部获取。

关于这个问题。当获取大量数据时,枚举过程“ToList()”需要好几秒钟,这加起来比预期的加载时间要长。根据 SQL Profiler,我的查询的典型持续时间约为 1500。对于 1000 条记录,ToList() 调用最多可能需要 4 秒,这似乎很极端。

我的主要问题是,有什么办法可以加快这个过程吗?或者也许有更好的方法将大量数据从数据库获取到 silverlight 应用程序?

附加信息:

我的 linq 引用被硬编码到我的数据上下文的部分类中。这是由于一个笨拙的存储过程,它的返回类型不能很好地与 dbml 文件配合使用。

我还创建了一个基本对象,我将它设置为我的对象的返回类型,主要由快速属性定义组成,例如:

 public Guid Id {get; set;} 

接下来的问题是,在定义 linq 存储过程调用和返回类型时,是否有任何属性可以帮助加快进程,或者我可以将其链接到一个非常基本的对象吗?

【问题讨论】:

  • 当您说“枚举最多可能需要 4 秒”时,您到底是什么意思?你有很多地方可能是这里的瓶颈。为了理智起见,我建议您将它们完全分开,以便我们知道发生了什么。
  • 对不起,如果我有点罗嗦。我的意思是在我调用我的存储过程之后,我的 ToList() 调用可能需要几秒钟,这似乎有点多。
  • 伙计,这段时间创建了多少对象?当您调用 ToList() 时,您是在创建数十个对象还是趋向于数千个对象?
  • 我将数据分成 1000 个块。确切地说,我跳过(1000*packetNo).Take(1000).ToList()。最多应该是 1000 个对象。

标签: c# linq silverlight


【解决方案1】:

首先你需要弄清楚瓶颈在哪里;通常的罪魁祸首:

  • 延迟;你提到了 3 个调用(而不是 300 个),所以我认为这不是问题
  • 带宽;您要发送的对象有多胖
  • 核心数据库查询性能;你的SELECT有多快
  • 延迟加载问题;你真的在做 n+1 db 操作吗?

使用 SQL 跟踪或一些简单的日志记录来调查最后两个(LINQ-to-SQL 有一个DataContext.Log 属性,在这里非常有用); SQL 跟踪可能更准确。

要调查从 Silverlight 客户端到 Web 服务器的次数是否是问题,请尝试网络跟踪; Fiddler 或 WireShark 应该可以完成这项工作。

如果带宽是问题(即通过网络传输大量数据),请考虑:

  • 压缩
  • 不同的序列化程序

例如,protobuf-net 可以对电线上的尺寸产生巨大的差异;不过,两者都可能需要稍微不同的代码 - 最简单的方法是通过服务传递 byte[](如果可能,使用 MTOM)。

【讨论】:

  • 我将数据库移到了本地,这让事情变得更加清晰。在数据库通过云之前,大约需要 4 秒才能回复我。我还枚举了所有 3000 多行,而我只取了 1000 行。从长远来看,我每次调用我的数据库的时间都超过一秒,而对我的网络的往返调用则超过 2 秒服务。还不错,但更高的权力需要更快的速度。我唯一能想到的就是试图找到一种方法来一次获取所有数据。这导致了stackoverflow.com/questions/1462452/silverlight-data-access 的一个新问题
【解决方案2】:

我猜你已经嵌套了一个 linq 查询,所以每次向前移动迭代器时,内部查询都会重新运行。如果这是您的情况,也许您想预先计算内部查询。

【讨论】:

    【解决方案3】:

    答案是完全停止使用 ToList()。不要将所有数据加载到 Web 服务中,然后将其作为一个巨大的 blob 提供给客户端。采取流式方法;所以而不是(伪代码)

    for each record in query;
      add record to list
    
    for each record in list;
      create a line of response
      write line to response.
    

    你不能像这样流式传输响应吗?

    for each record in query;
      create a line of response
      write line to response.
    

    您的 Web 服务中的 foreach 应该一次遍历一条记录的查询结果,并且内存使用量绝对是最低的。

    【讨论】:

      【解决方案4】:

      为避免必须使用 ToList(),请让您的 Web 服务代理生成使用 List 集合的代码。通过在 Visual Studio 项目中查找服务引用来执行此操作。右键单击 > 配置服务引用。然后在集合类型下,选择一个支持 linq 方法的集合。我会使用 System.Collection.Generic.List。然后更新服务引用以重新生成 References.cs 文件。

      【讨论】:

        猜你喜欢
        • 2014-06-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-12-10
        • 1970-01-01
        相关资源
        最近更新 更多