WCF数据序列化:它可以更快吗?

时间:2012-04-04 19:07:28

标签: wcf entity-framework serialization entity-framework-4 datacontractserializer

这个问题是that问题的续集。

当我们想要构建一个可以处理某种数据的WCF服务时,我们希望它能够快速高效地运行。为了实现这一目标,我们必须确保数据公路旅行的所有部分尽可能快地从数据存储后端(如SQL Server)到请求该数据的WCF客户端。

在寻求上一个问题的答案时,我们已经了解到,感谢Slauma和其他通过评论做出贡献的人,实体框架(第一个)大型查询的耗时部分是对象实现和附加实体到返回数据库结果的上下文。我们已经看到在后续查询中一切都运行得更快。

假设这些大型查询被用作只读操作,我们得出结论,我们可以将EF MergeOption设置为NoTracking,从而产生更好的首次查询性能。我们用NoTracking做的是告诉EF为从数据库中检索的每条记录创建单独的对象 - 即使它们具有相同的密钥。如果我们的查询中包含.Include()语句,这将导致额外的处理,这将导致返回更大的数据。

数据可能很大,我们可以很容易地问自己 - 我们是否真的通过使用NoTracking选项来帮助我们的事业,即使我们使查询更快(也许只是第一个,取决于数字.Include()语句,因为没有NoTracking选项和多个.Include()语句的后续查询运行得更快,因为NoTracking选项导致在从服务器返回数据时创建更多对象)?

最大的问题是如何有效地序列化这些数据 - 并在客户端上对其进行反序列化。序列化已经很慢(我使用DataContractSerializer并将PreserveObjectReferences设置为true因为我将EF 4.x生成的POCO发送到我的客户端,反之亦然),我们是想要生成更多数据(感谢NoTracking)?说实话,我还没有看到来自查询的数据{~1}}选项在~11000对象上,不包括通过NoTracking获得的导航属性,到达客户端。上次我尝试将其关闭时,00:10:00的超时被触发(!)

因此,如果你还在阅读这段文字,你告诉我如何解决这个问题。使用哪种序列化器才能达到可接受的效果?目前,如果我不使用.Include()选项,那么~11000的序列化,传输和反序列化,通过NoTracking - 就像本地机器上的自定义绑定需要大约5秒钟。对我来说可怕的是,这张大表最终可能会包含约500,000条记录。

3 个答案:

答案 0 :(得分:3)

您是否考虑过为对象创建视图模型并在select语句中进行投影。那应该快得多:

 var result = from person in DB.Entities.Persons
    .Include("District")
    .Include("District.City")
    .Include("District.City.State")
    .Include("Nationality")
    select new PersonViewModel()
    {
        Name = person.Name, 
        City = person.District.City, 
        State = person.District.City.State
        Nationality = person.Nationality.Name
    };

这将要求您创建一个ViewModel类来保存PersonViewModel的展平数据。

您可以通过创建数据库视图并让Entity Framework直接从那里进行选择来进一步加快速度。

如果你想让前端填充500.000条记录的网格,那么我将完全删除webservice层并使用DataReader加速进程。实体框架和WCF不适合以适当的性能转换数据。你在这里基本上做的是:

  

数据库 - > TDS - > .NET对象 - > XML - >纯文本 - > XML - > .NET对象 - > UI

虽然这很容易简化为:

  

数据库 - > TDS - > UI

然后使用EntityFramwork处理业务逻辑中实体的更改。这与命令和查询分隔模式一致。使用适合高性能数据查询的技术,并将其直接链接到您的应用程序。然后使用命令策略来实现业务逻辑。

OData服务还可以提供更好的方式将UI直接链接到数据,因为它可以用来快速查询数据,从而实现快速过滤,而无需用户真正注意到。

如果安全设置禁止直接通过OData查询或直接访问SQL数据库,请考虑自己实现对象。直接从视图或查询中选择数据,并使用IDataReader直接填充ViewModel。这可能会给你最高的性能。

创建实体框架有很多替代方案,特别是因为大型数据集不会删除EF。请参阅FluentData DapperDotNetMassivePetaPoco。您可能希望将这些与实体框架并排使用来处理大型扁平数据查询。

答案 1 :(得分:0)

我在我的RIA应用程序中使用Json.Net的Bson实现。 More info here.

当我从数据库中读取并序列化行时,我返回一个IEnumerable。我发现速度是可以接受的,我返回的实体大约有20个属性。这种方法应该最小化服务器上​​的并发内存使用。

答案 2 :(得分:0)

根据我通过查看各种评论和性能基准收集的内容,我会选择protobuf-net作为序列化程序。设计是否可以插入我的服务配置只是一个问题。有关here的更多信息。

虽然不完全是对这个问题的回答,jessehouwing得到了最好的答案,我将其标记为已被接受。