Kentico transformation method performanceThursday, September 22, 2016
Using data sources and viewers (think basic repeater and universal viewer) is a great way to get information on to your page. The inclusion of out-of-the-box transformation methods make formatting the information and displaying something useful to the end user a much simpler task. However, you must take care when using some out-of-the-box features that you are using the most performant method available.
Some of the methods available take considerably more time than others to complete, and often you can have the right data to hand such that you can dramatically reduce the amount of work that Kentico needs to do in order to get a response to your users.
Over the years, the research into the impact of TTFB (time to first byte) and its impact on SEO and sales conversions has been very conclusive. As consumers and users, we have really short attention spans these days, so everything that we can do to speed up page loads will help.
Consider the scenario that we want a page template that displays a list of page names as a non-paginated list of hyperlinks for all 1st level child pages of the current page. This sounds like a fairly straightforward solution, and we could solve it as follows:
- In our page template, add a new Data source web part and configure it to show the documents with the following settings:
- Web part control ID:
- Alias path:
- Maximum depth:
- Order by:
DocumentID, DocumentName, NodeAliasPath
- Web part control ID:
- Set up a Basic repeater that uses the Data source created in step 1. Configure the repeater as follows:
- Data source name:
- Content before:
- Content after:
- Transformation: Create a new transformation and provide the following ASCX code:
<li><a href=<%# GetDocumentUrl(Eval("DocumentID")) %>"><%# Eval("DocumentName") %></a></li>
- Data source name:
So, pretty straight forward. We’ll load our page and see what happens. Make sure that for this case, these are the only web parts on the template (no inheriting any master templates etc). On my test environment, 11 items are returned by the data source.
The TTFB on the first load is 760 ms, on third load its 260 ms. Pretty nice, but then it’s a simple list. When we look at the SQL debug, it’s a bit ‘busy’, even on the cached page. For each item returned by the data source, we have four separate queries back to the DB. It’s to be expected really, all we’ve done is provided the GetDocumentUrl method with an ID.
Kentico now has to figure out what to do with it and that roughly means:
Making sure it’s a real document and not a linked document, then selecting the most recent version of the document from the document history that also happens to be in the right culture version.
All of that creates 4 DB queries per item in the data source, so all in all we’re getting 44 DB queries on top of the original query. Now, if you look at the decompiled source of the
GetDocumentUrl method, you find out that, sooner or later, it calls another called
GetUrl. This method then takes a couple of parameters (all of which are easily available to us from the original data source).
Knowing that we call
GetUrl, let's change some things and see if we can improve the TTFB. Alter the Basic repeater as follows:
Transformation: Create a new transformation and provide the following ASCX code:
<li><a href=<%# GetUrl(Eval("NodeAliasPath"), null, CurrentSite.SiteName) %>"><%# Eval("DocumentName") %></a></li>
OK, so now when we load the page, the TTFB on the first load is 260ms, on third load its 20ms. Wow! The GetUrl method does not need to look up any information from the DB, it has everything it needs already and so returns much quicker.
Just put those results next to each other:
- 1st load: 760ms
- 3rd load: 260ms
- 1st load: 260ms
- 3rd load: 20ms
That’s a significant saving in time. Although it may seem small, we need to keep in mind that this is the only web part on the template. The more web parts, the more time will be taken - and time is money.
Looking at research by Mozilla on the impact of TTFB on search rankings, for example, lets us know that each tiny fraction can help. (Yes, I’m using the phrase TTFB, but we could also use the term Server Response Time, as that’s what I’m really looking at given I’m working with a local copy of Kentico - so I know that the network latency, etc. is a constant).
Anyway, I’m not saying that
GetDocumentUrl is bad - in some cases, it may be your only choice. The point of this article is to make you think whether the methods that you’re using in your transformations are appropriate for your needs. Heck - in our example it may well be that case that you could just use the raw alias path (that saves me another 5ms if you’re interested) since I know I’m not doing anything fruity with URL wildcards or alias paths in general.
The lesson is: always question whether there is something better that will give you an advantage in terms of the amount of time it will take to execute. Don’t always accept what you’ve used before; Kentico has a big bag of toys that is worth exploring and getting familiar with so that you can use the right one every time.