Recently, I've upgraded a website into Umbraco. Before I launched the website I used Mini Profiler to check that the website's web pages worked performantly. If you haven't come across MiniProfiler yet, I suggest you read, How To Debug Your Umbraco 7 Website. In today's tutorial, I'm going to cover some of the learning experiences I made with the Umbraco API and how I overcame them.
Umbraco Performance Issues
Use The Right API
So when I started off I looked at mini-profiler and I saw this. In my header, I was calling 60 repeat SQL calls. The first thing you should do when working with Umbraco is make sure you're usin gthe right API for the job. InUmbraco you can access data in two different ways, one with content and the other with IPublishedContent
Allows for read/write access to your Umbraco data. You may also need to use IContent if you need to access your content from outside of a Umbraco context, e.g. a API etc..
Is the much faster way to access your Umbraco data in a read-only mode. The API interacts with the Examine index and consequently talks to the "content cache" compared to the database.
Umbraco database calls are slow so when you're trying to display data on your website, it is recommended to work with IPublishedCOntent rather than accessing the database each request.
Get Desendants Vs Get Children
If you use IPublishCOntent you will get rid of a number of the issues I've listed above, however, let's just assume for this tutorial that you have to use IContent. In my header menu above, I had a second issue of redundant SQL queries that was due to the API call to get the menu items. This website used a mega-menu as the sites primary menu. Mega-menus have top-level items and then a number of sub-items. The first way I was getting the menu items was using GetChildren() to get through the top-level items and then if any of the menu items were set to display a mega-menu underneath it, use GetCHildren() again to get the extra data.
As you can see from the mini-profiler results, this was causing a lot of extra SQL calls. The more SQL calls your webpage has to make the slower it will be. Instead of having to make a number of SQL calls to get all the data I needed, it is a lot more efficient in this instance to use GetDescendants() and get all of your items in one SQL hit.
As you can see from the comparisons, I saved over 50 SQL queries per request form using the API in a slightly different way. Instead of using GetChildren numerous times and repeating a lot of the same SQL. I could use GetDescendants() once and then parse all the data in code.
I'd refactored the code to removed 51 requests. I was still suck with the 9 calls on first-page load. To get around this I simply put all the data into the cache for an hour. This means once an hour a page has to do a few more SQL calls than needed, but for 99% of the traffic they will get really quick page loads. The code to cache objects is really simple:
The code to add items into the cache would look like this:
Using these three techniques I got my 100 SQL queries from the first-page load, down to about 20 on first-page load, simply by using the API in a more efficient manner. As I'm hoping you can see, using the wrong API, or, using the wrong method can add a lot of lag onto your page load time. When it comes to performance, everyone no matter how experienced you are will need to bust out a tool to mini-profiler to help you figure out the slowest parts of your page.
When you try to make your pages faster, there are usually one or two pain points. In my example, it was the header that was making the page load slowly. Simply by using the right API and then calling that API in the most efficient manner, meant instead of using 60 unneeded SQL calls, I reduced it to 5
5 Still seemed quite wasteful, so I put my menu in the normal session cache, so on any other page load these duplicate SQL calls where removed. When it comes to performance there are loads of different ways to make your pages quicker. The aim of this tutorial was to guide you through the process of fine-tuning your pages. When it comes to Umbraco make sure you are using IPublishedContent!