Lately we noticed that the overall site performance went down a bit by adding a lot of new features. In the last couple of weeks we have been profiling the CMS to find the bottlenecks and resolve them. Below an overview of the most important improvements we released.

1) A better node hydrating strategy

The CMS supports different site languages out of the box. This means that a page can be edited/saved in different languages. There is also a system in place that creates a new version of the page on certain occasions, so that it is possible to revert pages to previous versions. To support those functionalities, there are 3 objects used in the database model: Node, NodeTranslation and NodeVersion.

When building and rendering a page, the CMS needs to access the node structure quite often. Before the improvements, the Node was fetched from the database, and when needed the NodeTranslations and NodeVersions were fetched separately. This was resulting in some extra queries that could be avoided by already hydrating the Node with the NodeTranslations and NodeVersions objects.

A special thanks to Khairi Husseini for his contribution on this improvement.

2) Database indexes

We analyzed the base CMS database tables to see if there were any modifications possible to speedup the queries. We noticed that there were some relevant indexes missing, and we changed some column types. These changes resulted in a decrease of the total query time.

3) NodeMenu speedups

The NodeMenu class is used for building the menu structures of the website: the different menu's, the footer doormat, the places where you need to fetch 1 menu item with it's internal name, ... and so on.

Before the changes, when you wanted to fetch the children of a specific menu item, a new query was fired. You can imagine that this resulted in a lot of queries when the site has many pages/menu's.

We improved the performance by fetching all menu nodes in one query, and storing them in a variable (in memory). When some child pages, or a page with a specific name is required, we do not need to do an extra query, but just do a lookup in the cached menu nodes. This change reduced the number of queries drastically, especially on medium and big sites.

4) Fetching pageparts in a more clever way

When the CMS renders a page, it first fetched all pageparts of that page separately and then renders them one-by-one. By doing this, a query is fired for each pagepart. We changed this so that the pageparts of the same type are fetched in one query. This change resulted in less queries for pages that have many pageparts of the same type.

5) Disabling the translations debug mode while developing

For a developer, a slow development version of the site can be frustrating. When you are not working on the translations system of the site, you can now turn of the debug mode of the TranslatorBundle. With this change, all translations will be cached instead of being fetched one by one from the database. To disable the debug mode in your environment, add the snippet below to your config_dev.yml

    debug: false

Summing up

While the changes above are clearly noticeable in our performance statistics of the sites we are running, but there is still some room for improvement. So when you have some spare time and find a way to improve the CMS, feel free to send us a PR on github.


Feel free to contact the author