简体   繁体   English

在 Dynamics 365 Customer Engagement 中检索审核数据的性能问题

[英]Performance issue of retrieving Audit data in Dynamics 365 Customer Engagement

We have a solution to retrieve audit data from Dynamics 365 Customer Engagement.我们有一个从 Dynamics 365 Customer Engagement 检索审计数据的解决方案。 Since March 2019, we are running into quite some performance issue or timeout or error message in retrieving audit data.自 2019 年 3 月以来,我们在检索审计数据时遇到了相当多的性能问题、超时或错误消息。 Please see end of post for some exception message details.有关一些异常消息的详细信息,请参阅文章末尾。

We are using RetrieveMultipleRequest and fetch XML to retrieve IDs for audit data and then retrieve details by using RetrieveAuditDetailsRequest based on those audit record IDs.我们使用 RetrieveMultipleRequest 并获取 XML 来检索审计数据的 ID,然后使用基于这些审计记录 ID 的 RetrieveAuditDetailsRequest 检索详细信息。 Please see end of post for fetch XML.请参阅文章末尾获取 XML。 The first run would only have le condition (less than current timestamp) and subsequent runs would have gt and le for about 6 hours time range.第一次运行将只有 le 条件(小于当前时间戳),随后的运行将在大约 6 小时的时间范围内具有 gt 和 le。

We used to have 500 as batch size for both ID and details retrieval, and audit retrieval was good.我们曾经有 500 作为 ID 和详细信息检索的批大小,审计检索很好。 During Audit Details retrieval, we are getting TimeoutException ( we have 10 minute time out right now) or ObjectDisposedException ( see end of post for full stacks) even for small amount of records in some cases.在审核详细信息检索期间,即使在某些情况下,对于少量记录,我们也会收到 TimeoutException(我们现在有 10 分钟的超时时间)或 ObjectDisposedException(有关完整堆栈的信息,请参见文章结尾)。 We reduced the batch size for detailed record retrieval to 200 while keeping ID retrieval to 500 to reduce the load on CRM env, it seems that it helps.我们将详细记录检索的批量大小减少到 200,同时将 ID 检索保持到 500,以减少 CRM 环境的负载,这似乎有所帮助。

In some run we have in customer Dynamics env, the retrieval rate is about 0.7 record/per second for various batch size ranging from 50 to 400. The performance is quite poor here.在我们在客户 Dynamics 环境中的某些运行中,对于从 50 到 400 的各种批量大小,检索率约为每秒 0.7 条记录。这里的性能非常差。

Based on CRM on premise, here is the Audit table structure:以CRM为前提,Audit表结构如下:

CREATE TABLE [dbo].[AuditBase](
   [AttributeMask] [nvarchar](max) NULL,
   [TransactionId] [uniqueidentifier] NOT NULL,
   [Action] [int] NULL,
   [ObjectId] [uniqueidentifier] NOT NULL,
   [ObjectIdName] [nvarchar](1) NULL,
   [UserId] [uniqueidentifier] NOT NULL,
   [ChangeData] [nvarchar](max) NULL,
   [CreatedOn] [datetime] NOT NULL,
   [Operation] [int] NOT NULL,
   [AuditId] [uniqueidentifier] NOT NULL,
   [CallingUserId] [uniqueidentifier] NULL,
   [ObjectTypeCode] [int] NULL,
   [RegardingObjectId] [uniqueidentifier] NULL,
   [RegardingObjectIdName] [nvarchar](4000) NULL,
   [UserAdditionalInfo] [nvarchar](400) NULL
)
GO
ALTER TABLE [dbo].[AuditBase] ADD  DEFAULT (newsequentialid()) FOR [AuditId]

Note that there is no key at all and the audit data for all entities would be stored in the same table.请注意,根本没有键,所有实体的审计数据将存储在同一个表中。 Plus we are retrieving the record with some gt and le condition, will CRM backup sort the records by “CreatedOn” as well?另外,我们正在检索具有某些 gt 和 le 条件的记录,CRM 备份是否也会按“CreatedOn”对记录进行排序? With sorting, the retrieval would definitely be slow although I am not sure what amount of data it is sorting internally.通过排序,检索肯定会很慢,尽管我不确定它在内部排序的数据量是多少。

Anyone could shed some lights on this?任何人都可以对此有所了解吗?

[Update] : we tried by using a Fetch XML with less condition by followings the suggestions below in the answer, see below [Fetch XML 2], it won't help much either. [更新] :我们尝试按照以下答案中的建议使用条件较少的 Fetch XML,请参见下文 [Fetch XML 2],它也无济于事。 Right now the performance bottleneck is not at Audit ID retrieval, rather the audit details retrieval.目前,性能瓶颈不在于审计 ID 检索,而在于审计详细信息检索。


Fetch XML:获取 XML:

    <fetch no-lock='true'>
    <entity name='audit'>
        <filter type='and' >
            <condition attribute='operation' operator='in' >
                <value>2</value>
                <value>3</value>
            </condition>
            <condition attribute='action' operator='not-in' >
                <value>14</value>
                <value>15</value>
                <value>48</value>
                <value>49</value>
                <value>53</value>
                <value>54</value>
                <value>55</value>
                <value>56</value>
                <value>57</value>
                <value>58</value>
                <value>59</value>
                <value>60</value>
                <value>62</value>
                <value>63</value>
                <value>64</value>
                <value>65</value>
                <value>100</value>
                <value>101</value>
                <value>102</value>
                <value>103</value>
                <value>104</value>
                <value>105</value>
                <value>106</value>
                <value>107</value>
                <value>108</value>
                <value>109</value>
                <value>110</value>
                <value>111</value>
                <value>112</value>
                <value>113</value>
            </condition>
            <condition attribute='objecttypecode' operator='eq' value='1' />
            <condition attribute='createdon' operator='gt' value='2019-06-18T10:01:13.8571635Z' />
            <condition attribute='createdon' operator='le' value='2019-06-18T16:00:53.9247159Z' />
        </filter>
    </entity>
</fetch>

Fetch XML 2:获取 XML 2:

<fetch no-lock='true'>
  <entity name='audit'>
  <attribute name='auditid' />
  <filter type='and' >
    <condition attribute='objecttypecode' operator='eq' value='1' />
    <condition attribute='createdon' operator='gt' value='2020-01-18T16:01:13.8571635Z' />
    <condition attribute='createdon' operator='le' value='2020-02-13T16:00:53.9247159Z' />
  </filter>
 </entity>
</fetch>

Exception 1:例外 1:

    System.ObjectDisposedException: Cannot access a disposed object.
Object name: 'System.ServiceModel.Security.TransportSecurityProtocol'.
Server stack trace: 
at System.ServiceModel.Channels.CommunicationObject.ThrowIfClosedOrNotOpen()
at System.ServiceModel.Security.TransportSecurityProtocol.VerifyIncomingMessage(Message& message, TimeSpan timeout)
at System.ServiceModel.Security.SecurityProtocol.VerifyIncomingMessage(Message& message, TimeSpan timeout, SecurityProtocolCorrelationState[] correlationStates)
at System.ServiceModel.Channels.SecurityChannelFactory`1.SecurityRequestChannel.ProcessReply(Message reply, SecurityProtocolCorrelationState correlationState, TimeSpan timeout)
at System.ServiceModel.Channels.SecurityChannelFactory`1.SecurityRequestChannel.Request(Message message, TimeSpan timeout)
at System.ServiceModel.Dispatcher.RequestChannelBinder.Request(Message message, TimeSpan timeout)
at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)
at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)
at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)
Exception rethrown at [0]: 
at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
at Microsoft.Xrm.Sdk.IOrganizationService.Execute(OrganizationRequest request)

Exception 2:例外 2:

    System.TimeoutException: The request channel timed out while waiting for a reply after 00:09:59.9990005. Increase the timeout value passed to the call to Request or increase the SendTimeout value on the Binding. The time allotted to this operation may have been a portion of a longer timeout. ---> System.TimeoutException: The HTTP request to 'https://xxx.dynamics.com/XRMServices/2011/Organization.svc' has exceeded the allotted timeout of 00:10:00. The time allotted to this operation may have been a portion of a longer timeout. ---> System.Net.WebException: The operation has timed out
   at System.Net.HttpWebRequest.GetResponse()
   at System.ServiceModel.Channels.HttpChannelFactory`1.HttpRequestChannel.HttpChannelRequest.WaitForReply(TimeSpan timeout)
   --- End of inner exception stack trace ---
   at System.ServiceModel.Channels.HttpChannelUtilities.ProcessGetResponseWebException(WebException webException, HttpWebRequest request, HttpAbortReason abortReason)
   at System.ServiceModel.Channels.HttpChannelFactory`1.HttpRequestChannel.HttpChannelRequest.WaitForReply(TimeSpan timeout)
   at System.ServiceModel.Channels.RequestChannel.Request(Message message, TimeSpan timeout)
   --- End of inner exception stack trace ---
Server stack trace: 
   at System.ServiceModel.Channels.RequestChannel.Request(Message message, TimeSpan timeout)
   at System.ServiceModel.Channels.SecurityChannelFactory`1.SecurityRequestChannel.Request(Message message, TimeSpan timeout)
   at System.ServiceModel.Dispatcher.RequestChannelBinder.Request(Message message, TimeSpan timeout)
   at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)
   at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)
   at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)
Exception rethrown at [0]: 
   at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
   at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
   at Microsoft.Xrm.Sdk.IOrganizationService.Execute(OrganizationRequest request)
   at Microsoft.Xrm.Sdk.Client.OrganizationServiceProxy.ExecuteCore(OrganizationRequest request)
   at Microsoft.Xrm.Sdk.Client.OrganizationServiceProxy.Execute(OrganizationRequest request)

The number of conditions in that FetchXML might be contributing to the issue.该 FetchXML 中的条件数量可能导致该问题。 My thoughts are:我的想法是:

  1. See if you can enlist Microsoft Support to help you add custom indexes to ObjectTypeCode, Operation, Action, and CreatedOn, or perhaps a "covering index" for this particular query.看看您是否可以争取 Microsoft 支持来帮助您向 ObjectTypeCode、Operation、Action 和 CreatedOn 添加自定义索引,或者可能是此特定查询的“覆盖索引”。

  2. Narrow down the conditions considerably - see how it performs with only the ObjectTypeCode and CreatedOn conditions.显着缩小条件 - 看看它仅在 ObjectTypeCode 和 CreatedOn 条件下如何执行。 Then do the additional filtering in memory.然后在内存中进行额外的过滤。 Yes, you'll retrieve more records, but the speed increase of filtering in RAM might be worth it.是的,您将检索更多记录,但在 RAM 中提高过滤速度可能是值得的。

  3. You may also want to experiment with retrieving only certain columns, rather than the whole entity.您可能还想尝试只检索某些列,而不是整个实体。 One approach would be on the first pass to retrieve only the columns needed to do the filtering and page through those to get the ID's of the actual records you want.一种方法是在第一次通过时仅检索进行过滤所需的列,然后翻阅这些列以获取您想要的实际记录的 ID。 Then maybe page through the ID's and issue a Fetch with say 50 ID's at a time to retrieve the rest of the columns for those records.然后可能会翻阅 ID 并发出一次带有 50 个 ID 的 Fetch,以检索这些记录的其余列。

  4. In the interest of keeping the audit data set as small as possible, if you have any processes or apps that updating Account records, make sure they are updating only the necessary columns.为了使审计数据集尽可能小,如果您有任何更新帐户记录的进程或应用程序,请确保它们只更新必要的列。 If the audit history is showing a lot of unchanged data getting pushed back into the same fields, you may be able to update your code to pare down the fields that are getting updated.如果审计历史显示大量未更改的数据被推回相同的字段,您可以更新代码以减少正在更新的字段。

  5. Perhaps look into the option of exporting the audit data to SQL.也许研究一下将审计数据导出到 SQL 的选项。

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

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