Skip to main content

.GetItems() Slower than .GetListItems() - Is It Not?

An old-school Tridion best practice says "whenever possible try to use GetListItems over GetItems due to significant performance degradation on the latter". Now that might have been very well possible on the old TOM (Tridion Object Model). But is it still the case with TOM.NET? Let's see...

In my previous three posts, I have been playing with several ways of generating navigation XML based on Structure Groups and Pages:
  • Generate Structure Group Navigation - GetItems TBB - gets all SGs and Pages in one call to .GetItems() using a filter with Recursive=true. It then iterates the list of objects and creates an XML document using the hierarchy given by the items' OrganizationalItem property;
  • Generate Structure Group Navigation - Reorder TBB - gets all SGs and Pages in one call to .GetListItems() using a filter with Recursive=true. It then iterates the flat XML, instantiates SG and Page objects using the Engine.GetObject() method, and uses the .OrganizationalItem property to reorder the XML nodes into a hierarchical structure that matches the SG/Page nesting;
  • Generate Structure Group Navigation - Recursive TBB - gets SGs and Pages directly under the current Structure Group by making a call to .GetListItems() using a filter with Recursive=false. For each child SG, it calls itself recursively, and adds the returned items to their direct parent;
So the question is - which approach performs the best?

I conducted the tests on a Tridion 2013 GA instance that had 221 Structure Groups and 2173 Pages, running on my VMWare image on Windows Server 2008 R2 Standard, 4GB RAM, dual core 2.40GHz.

The results were surprising, at least to me:
  • GetItems TBB - 45 seconds;
  • Reorder TBB - 45 seconds;
  • Recursive TBB - 43 seconds;
I was expecting to see the Reorder TBB and Recursive TBB (using .GetListItems) clock significant lower execution time than GetItems TBB (using .GetItems).

And in fairness, it does clock significantly lower, if we strictly look at the execution of .GetListItems vs .GetItems (Reorder TBB executes .GetListItems in ~1 second vs 44 seconds it takes GetItems TBB to retrieve the objects).

However, Reorder TBB and Recursive TBB have to instantiate the actual SG and Page objects, because the XML returned by .GetListItems doesn't contain enough information to generate the navigation XML (i.e. it's missing URL and potentially other metadata). There is also some overhead in creating the hierarchical structure (iterating over nodes, appending them to different parents, removing unused nodes, etc). This is why in the end, the Recursive TBB is the fastest, because it doesn't have to restructure the retrieved XML. Instead, it constructs it as it is searching.

This makes the total execution time almost the same. In other words,
T(.GetListItems) + T(Engine.GetObject for each SG/Page) = T(.GetItems)

So to conclude -- yes, .GetListItems is significantly faster than .GetItems and whenever possible, by all means do use it. In my case, I actually needed the SG/Page objects, so I had to instantiate them. This is really where the time is consumed ultimately.


Rick said…
Note that in recent versions of SDL Tridion (2011 SP1 and higher), the TOM.NET partially pre-loads the objects returned by .GetItems. That means that all data you get out of .GetListItems will be mapped to the associated properties in the TOM.NET object. Accessing these pre-loaded TOM.NET object properties is cheap; it won't cause the object to be fully loaded. Only when you access a property which is not pre-loaded (not part of the list data) will a full load occur.
As long as you only access pre-loaded properties, using .GetItems will even be faster than .GetListItems (which has to build list XML based on those same pre-loaded data)!
Mihai Cădariu said…
Good comment, thanks Rick!

I noticed the call to .GetItems() is also very fast (~1s), but then iterating over the results and accessing their properties is where time is spent -- in line with what you're saying.

Popular posts from this blog

Content Delivery Monitoring in AWS with CloudWatch

This post describes a way of monitoring a Tridion 9 combined Deployer by sending the health checks into a custom metric in CloudWatch in AWS. The same approach can also be used for other Content Delivery services. Once the metric is available in CloudWatch, we can create alarms in case the service errors out or becomes unresponsive. The overall architecture is as follows: Content Delivery service sends heartbeat (or exposes HTTP endpoint) for monitoring Monitoring Agent checks heartbeat (or HTTP health check) regularly and stores health state AWS lambda function: runs regularly reads the health state from Monitoring Agent pushes custom metrics into CloudWatch I am running the Deployer ( installation docs ) and Monitoring Agent ( installation docs ) on a t2.medium EC2 instance running CentOS on which I also installed the Systems Manager Agent (SSM Agent) ( installation docs ). In my case I have a combined Deployer that I want to monitor. This consists of an Endpoint and a

Running sp_updatestats on AWS RDS database

Part of the maintenance tasks that I perform on a MSSQL Content Manager database is to run stored procedure sp_updatestats . exec sp_updatestats However, that is not supported on an AWS RDS instance. The error message below indicates that only the sa  account can perform this: Msg 15247 , Level 16 , State 1 , Procedure sp_updatestats, Line 15 [Batch Start Line 0 ] User does not have permission to perform this action. Instead there are several posts that suggest using UPDATE STATISTICS instead: I stumbled upon the following post from 2008 (!!!), , which describes a way to wrap the call to sp_updatestats and execute it under a different user: create procedure dbo.sp_updstats with execute as 'dbo' as

Event System to Create Mapped Structure Groups for Binary Publish

As a continuation of last week's Publish Binaries to Mapped Structure Group , this week's TBB is in fact the Event System part of that solution. Make sure you do check out the previous post first, which explains why and what this Event System does. To reiterate, the Event System intercepts a Multimedia Component save, take its Folder path and create a 1-to-1 mapping of Structure Groups. The original code was written, again, by my colleague Eric Huiza : [ TcmExtension ( "MyEvents" )] public class EventsManager  : TcmExtension {     private Configuration configuration;     private readonly Regex SAFE_DIRNAME_REGEX = new Regex ( @"[\W_]+" );     public EventsManager() {         ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap ();         fileMap.ExeConfigFilename = Path .GetDirectoryName( Assembly .GetExecutingAssembly().Location) + "\\EventSystem.config" ;         configuration = ConfigurationManager