Pogo69's Blog

April 5, 2012

CRM 2011 – CRUD vs Execute – Which is Faster?

Filed under: C#, CRM, Cutting Code — pogo69 [Pat Janes] @ 12:35

Overview

An interesting discussion began on the MSDN Support Forums for CRM Development recently; regarding the performance of the various Web Service CRUD methods compare to their Execute wrapped equivalents.

According to the SDK:

http://msdn.microsoft.com/en-us/library/42dcebf5-a624-45b9-b719-20e5882d5ca2(MSDN.10)#Performance

We are encouraged to use the CRUD methods as they are faster:

Use Common Methods

The common methods are faster than using the Execute method together with the corresponding message. The following table lists these methods and messages.

Method Message
Create CreateRequest
Delete DeleteRequest
Update UpdateRequest
Retrieve RetrieveRequest
RetrieveMultiple RetrieveMultipleRequest

The obvious question was raised – why?

I gave an initial hypothesis which, while it seemed quite valid, was admittedly an educated guess at best.  Upon being challenged, I decided to dig deeper.  You can see the results of that discussion in the originating thread:

http://social.msdn.microsoft.com/Forums/en/crmdevelopment/thread/8d679824-8cd6-4a27-ad4d-11974dc5403b

Decompiling is Your Friend

Although peeking inside the inner workings of the CRM is largely discouraged, I find it an extremely useful exercise from time to time.  Not only do I occasionally learn something about the way the CRM implements certain mechanisms, it has on occasion, allowed me to see a solution that I may otherwise have either never found or done so only by trial and error.  This is particularly the case for areas in which the SDK documentation describes only the relevant API (the what and to some extent the how) and not the where, when and why.

In this case, I ripped apart only enough of the relevant assemblies to verify that as per the hypothesis in another thread linked in the one discussed here, the “Create” message and its other CRUD siblings, are “wrapped” in an call to Execute.  As I mention in my final reply however, the Execute web service call carries its own overhead in that the inner message must be extracted.  Without digging too deep (or going nuts and decompiling the entire application and running some profiling software over it), it appeared to me that things were about even with respect to performance.

Reality (The Results are In!!)

In the end; it doesn’t really matter what the SDK says; it doesn’t really matter what a code analysis says.  It matters only what your real world experiences are (THE END RESULT) when you attempt to use these mechanisms.  So I wrote some code and came to my own conclusions, with the code and results as follows:

<pre>System.Diagnostics.Stopwatch stopWatchCreate = new System.Diagnostics.Stopwatch();
System.Diagnostics.Stopwatch stopWatchExecute = new System.Diagnostics.Stopwatch();

using (var xrm = new Xrm2011.XrmServiceContext("MrCRM.Dev"))
{
	xrm.MergeOption = Microsoft.Xrm.Sdk.Client.MergeOption.NoTracking;

	WhoAmIRequest reqWhoAmI = new WhoAmIRequest();
	WhoAmIResponse respWhoAmI = (WhoAmIResponse)xrm.Execute(reqWhoAmI);

	for (int i = 0; i < 10000; i++)
	{
		// execute
		stopWatchExecute.Start();

		{
			CreateRequest req = new CreateRequest
			{
				Target = new Entity
				{
					LogicalName = "contact"
				}
			};
			req.Target.Attributes.AddRange(
				new KeyValuePair<string, object>("firstname", string.Format("Person{0}", i)),
				new KeyValuePair<string, object>("lastname", string.Format("Name{0}", i)),
				new KeyValuePair<string, object>("telephone1", string.Format("555-{0:0000}", i)),
				new KeyValuePair<string, object>("telephone2", string.Format("554-{0:0000}", i)),
				new KeyValuePair<string, object>("telephone3", string.Format("553-{0:0000}", i)),
				new KeyValuePair<string, object>("address1_line1", string.Format("{0} Place Street", i)),
				new KeyValuePair<string, object>("address1_city", string.Format("CityVille{0}", i)),
				new KeyValuePair<string, object>("address1_stateorprovince", string.Format("State{0}", i)),
				new KeyValuePair<string, object>("address1_postalcode", string.Format("553-{0:0000}", i))
			);

			CreateResponse resp = (CreateResponse)xrm.Execute(req);
		}

		stopWatchExecute.Stop();

		// create
		stopWatchCreate.Start();

		{
			Entity target = new Entity
			{
				LogicalName = "contact"
			};
			target.Attributes.AddRange(
				new KeyValuePair<string, object>("firstname", string.Format("Person{0}", i)),
				new KeyValuePair<string, object>("lastname", string.Format("Name{0}", i)),
				new KeyValuePair<string, object>("telephone1", string.Format("555-{0:0000}", i)),
				new KeyValuePair<string, object>("telephone2", string.Format("554-{0:0000}", i)),
				new KeyValuePair<string, object>("telephone3", string.Format("553-{0:0000}", i)),
				new KeyValuePair<string, object>("address1_line1", string.Format("{0} Place Street", i)),
				new KeyValuePair<string, object>("address1_city", string.Format("CityVille{0}", i)),
				new KeyValuePair<string, object>("address1_stateorprovince", string.Format("State{0}", i)),
				new KeyValuePair<string, object>("address1_postalcode", string.Format("553-{0:0000}", i))
			);
			xrm.Create(target);
		}

		stopWatchCreate.Stop();
	}
}

System.Diagnostics.Debug.Print("Create:\t{0} milliseconds", stopWatchCreate.ElapsedMilliseconds);
System.Diagnostics.Debug.Print("Execute:\t{0} milliseconds", stopWatchExecute.ElapsedMilliseconds);

I tried to make it as “fair” as possible by:

  • Preceding the real code with a WhoAmI request to initialise the connection
  • Interspersing the calls
  • Running the entire thing twice, wherein the 1st iteration placed the Create 1st, Execute 2nd; and the 2nd iteration reversed as above

The results?

Create wins!!  But only marginally, particularly given we’re creating 10,000 records and the difference was quite small.

Create: 382873 milliseconds
Execute: 384767 milliseconds

Create: 404256 milliseconds
Execute: 406978 milliseconds

Conclusion

So, I would say that all in all:

  1. Unless you NEED to scrounge every last millisecond of performance out of your application, code whichever way you prefer
  2. Don’t blindly believe everything you read in the SDK – test and confirm

Thanks to Laughing John for the inspiration.

Advertisements

Leave a Comment »

No comments yet.

RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Blog at WordPress.com.

%d bloggers like this: