简体   繁体   English

从CRM加载数据的性能问题

[英]Performance issue loading data from CRM

Currently our website is facing a problem with slow response times (more than 1 min) when we query CRM from our website. 目前,当我们从我们的网站查询CRM时,我们的网站面临着响应时间较慢(超过1分钟)的问题。 We are using CRM 2011 though a web service. 我们通过Web服务使用CRM 2011。 When we investigated we found that the time was spent at the point of querying CRM. 当我们调查时,我们发现在查询CRM时花费的时间。

We have used the CrmSvcUtil.exe to generate our proxy classes that map to CRM entities. 我们使用CrmSvcUtil.exe生成映射到CRM实体的代理类。 Then we create an instance of context and query CRM using LINQ with C#. 然后我们使用LINQ和C#创建上下文实例并查询CRM。

When we query, We load our parent object with LINQ to CRM and then we use LoadProperty to load the related children. 当我们查询时,我们使用LINQ加载我们的父对象到CRM,然后我们使用LoadProperty加载相关的子项。

I would like to know if anyone out there using a different method of querying CRM, and if you have come across issues like this in your implementation. 我想知道是否有人使用不同的方法查询CRM,如果你在实现中遇到过这样的问题。

I've included a simplified sample query below. 我在下面列出了一个简化的示例查询。

    public void SelectEventById(Guid id)
     {
            var crmEventDelivery = this.ServiceContext.EventDeliverySet.FirstOrDefault(eventDelivery => eventDelivery.Id == id);
            if (crmEventDelivery != null)
            {
              this.SelectCrmEventDeliveryWithRelationships(crmEventDelivery);
            }
    }

    private void SelectCrmEventDeliveryWithRelationships(EventDelivery crmEventDelivery)
     {
            // Loading List of Venue Delivery on parent crmEventDelivery thats been passed
            this.ServiceContext.LoadProperty(crmEventDelivery, Attributes.EventDelivery.eventdelivery_venuedelivery);

            foreach (var venueDelivery in crmEventDelivery.eventdelivery_venuedelivery)
            {
                 // Loading Venue on each Venue Delivery
                 ServiceContext.LoadProperty(venueDelivery, Attributes.VenueDelivery.venue_venuedelivery);
            }

            // Loading List of Session Delivery on parent crmEventDelivery thats been passed
            this.ServiceContext.LoadProperty(crmEventDelivery, Attributes.EventDelivery.eventdelivery_sessiondelivery);

            foreach (var sessionDelivery in crmEventDelivery.eventdelivery_sessiondelivery)
            {
              // Loading Presenters on each Session Delivery
              ServiceContext.LoadProperty(sessionDelivery, Attributes.SessionDelivery.sessiondelivery_presenterbooking);
            }
   }

Based on what you've provided this looks like a standard lazy-load issue, except my guess is that each lazy load is resulting in a web service call. 根据您提供的内容,这看起来像标准的延迟加载问题,除了我的猜测是每个延迟加载导致Web服务调用。 This would be called a "chatty" service architecture. 这将被称为“健谈”服务架构。 Your goal should be to make as few service calls as possible to retrieve data for a single request. 您的目标应该是尽可能少的服务调用来检索单个请求的数据。

Calling to fill in details can seem like a good idea because you can re-use the individual service methods for cases where you only want data 1 or 2 levels deep, or all the way down, but you pay a steep performance penalty. 调用填写详细信息似乎是一个好主意,因为您可以重复使用各种服务方法,以便您只需要1或2级数据,或者一直向下,但是您需要付出陡峭的性能损失。

You would be better off defining a web service call that returns a complete object graph in scenarios like this. 您最好定义一个Web服务调用,在这种情况下返回一个完整的对象图。 I don't know if/what you're using for an ORM layer within the CRM but if you make a specific call to fetch a complete graph of Deliveries then the ORM can eager-fetch the data into fewer SQL statements. 我不知道您在CRM中是否使用了ORM层,但如果您进行特定调用以获取交付的完整图表,那么ORM可以将数据急切地提取到更少的SQL语句中。 Fewer calls to the web service (and subsequently fewer calls into the CRM's data store) should noticeably improve your performance. 对Web服务的调用次数减少(以及随后对CRM数据存储的调用次数减少)会显着提高您的性能。

Like mentioned on the other answers your main problem is the number of web service calls. 就像在其他答案中提到的那样,您的主要问题是Web服务调用的数量。 What no one mentioned is that you can retrieve many objects with a single call using query joins. 没有人提到的是你可以使用查询连接通过一次调用来检索许多对象。 So you could try something like: 所以你可以尝试这样的事情:

var query_join = (from e in ServiceContext.EventDeliverySet
                         join v in ServiceContext.VenueDeliverySet on e.EventDeliveryId equals v.EvendDeliveryId.Id
                         join vn in ServiceContext.VenueSet on v.VenueDeliveryId equals vn.VenueDeliveryId.Id
                         join s in ServiceContext.SessionDeliverSet on e.EventDeliveryId equals s.EvendDeliveryId.Id
                         where e.EventDeliveryId == id // *improtant (see below)
                         select new { EventDelivery = e, VenueDelivery = v, Venue = vn, SessionDeliver = s }).ToList();

Then you can run a foreach on query_join and put it together. 然后你可以在query_join上运行foreach并将它放在一起。

***improtant: do not use the base Id property (e.Id), stick with e.EntityNameId.Value (don't know why but it took a while for me to figure it out. Id returns default Guid value "00000.."). *** improtant:不要使用base Id属性(e.Id),坚持使用e.EntityNameId.Value(不知道为什么但是我需要一段时间来弄明白.Id返回默认Guid值“00000 ..“)。

So I can see why this might take a while. 所以我可以看出为什么这可能需要一段时间。 I think as everyone else have commented you are making quite a few web service calls. 我想其他人都评论说你正在做很多网络服务电话。 If you get a moment it would be interesting to know if the individual calls are slow or its just because you are making so many, I would suggest profiling this. 如果你得到片刻的话,知道个别电话是否很慢或仅仅是因为你制作了这么多电话会很有趣,我建议对此进行分析。

In any case I suspect you would get better performance by not using the strongly type entities. 在任何情况下,我怀疑你不会使用强类型实体会获得更好的性能。

I would suggest using a FetchXml query, this will allow you to build a Sql Xml-Style query. 我建议使用FetchXml查询,这将允许您构建Sql Xml样式查询。 Basically you should be able to replace your many we bservice calls with a single call. 基本上你应该可以用一个电话替换你的许多我们的bservice电话。 The MSDN has an example, also check out the Stunnware FetchXml designer, Products > Stunnware Tools > Download and Evaluation. MSDN有一个例子,还可以看看Stunnware FetchXml设计器,产品> Stunnware工具>下载和评估。 It was built for Crm 4 but supports virtually all the features you will need. 它是为Crm 4而构建的,但几乎支持您需要的所有功能。

If you dont fancy that, you could also try a QueryExpression or OData , both of which should allow you to get your data in one hit. 如果你不喜欢它,你也可以尝试QueryExpressionOData ,这两者都应该允许你一次性获取你的数据。

After trying all the suggested tips in the other answers and doing further profiling, in our particular scenario with our use of CRM, and how it was set up - we decided to simply bypass it . 在尝试了其他答案中的所有建议提示并进行进一步的分析之后,在我们使用CRM的特定场景中,以及它是如何设置的 - 我们决定简单地绕过它

We ended up using some of the in-built views, this is not a recommended approach in the CRM documentation, but we really needed to achieve higher performance and the CRM approach in this instance was just in our way. 我们最终使用了一些内置视图,这不是CRM文档中推荐的方法,但我们确实需要实现更高的性能,而在这种情况下,CRM方法就是我们的方式。

To anyone else reading this, see the other answers too. 对于其他阅读此内容的人,请参阅其他答案。

Because the query does not know what fields will be needed later, all columns are returned from the entity when only the entity is specified in the select clause. 由于查询不知道以后将需要哪些字段,因此当只在select子句中指定实体时,将从实体返回所有列。 In order to specify only the fields you will use, you must return a new object in the select clause, specifying the fields you want to use. 要仅指定要使用的字段,必须在select子句中返回一个新对象,指定要使用的字段。

So instead of this: 所以不是这样的:

var accounts = from acct in xrm.AccountSet
               where acct.Name.StartsWith("Test")
               select acct;

Use this: 用这个:

var accounts = from acct in xrm.AccountSet
               where acct.Name.StartsWith("Test")
               select new Account()
               {
                   AccountId = acct.AccountId,
                   Name = acct.Name
               };

Check out this post more details. 看看这篇文章的更多细节。

To Linq or not to Linq 要Linq还是不要Linq

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM