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.


Comments

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

Toolkit - Dynamic Content Queries

This post if part of a series about the  File System Toolkit  - a custom content delivery API for SDL Tridion. This post presents the Dynamic Content Query capability. The requirements for the Toolkit API are that it should be able to provide CustomMeta queries, pagination, and sorting -- all on the file system, without the use third party tools (database, search engines, indexers, etc). Therefore I had to implement a simple database engine and indexer -- which is described in more detail in post Writing My Own Database Engine . The querying logic does not make use of cache. This means the query logic is executed every time. When models are requested, the models are however retrieved using the ModelFactory and those are cached. Query Class This is the main class for dynamic content queries. It is the entry point into the execution logic of a query. The class takes as parameter a Criterion (presented below) which triggers the execution of query in all sub-criteria of a Criterio

A DD4T.net Implementation - Custom Binary Publisher

The default way to publish binaries in DD4T is implemented in class DD4T.Templates.Base.Utils.BinaryPublisher and uses method RenderedItem.AddBinary(Component) . This produces binaries that have their TCM URI as suffix in their filename. In my recent project, we had a requirement that binary file names should be clean (without the TCM URI suffix). Therefore, it was time to modify the way DD4T was publishing binaries. The method in charge with publishing binaries is called PublishItem and is defined in class BinaryPublisher . I therefore extended the BinaryPublisher and overrode method PublishItem. public class CustomBinaryPublisher : BinaryPublisher { private Template currentTemplate; private TcmUri structureGroupUri; In its simplest form, method PublishItem just takes the item and passes it to the AddBinary. In order to accomplish the requirement, we must specify a filename while publishing. This is the file name part of the binary path of Component.BinaryConten

Scaling Policies

This post is part of a bigger topic Autoscaling Publishers in AWS . In a previous post we talked about the Auto Scaling Groups , but we didn't go into details on the Scaling Policies. This is the purpose of this blog post. As defined earlier, the Scaling Policies define the rules according to which the group size is increased or decreased. These rules are based on instance metrics (e.g. CPU), CloudWatch custom metrics, or even CloudWatch alarms and their states and values. We defined a Scaling Policy with Steps, called 'increase_group_size', which is triggered first by the CloudWatch Alarm 'Publish_Alarm' defined earlier. Also depending on the size of the monitored CloudWatch custom metric 'Waiting for Publish', the Scaling Policy with Steps can add a difference number of instances to the group. The scaling policy sets the number of instances in group to 1 if there are between 1000 and 2000 items Waiting for Publish in the queue. It also sets the