I decided to try profiling my quiz application to see if I could speed it up. Not surprisingly, biggest performance penalties came from loading classes and Doctrine’s ORM magic.
Here are some findings on how to improve performance.
As you may have heard, optimizing without profiling first is a bad idea, as you may think something is slow when something completely different would be better to optimize.
So for the profiling purproses, I configured Xdebug to output cachegrind files, and installed KCachegrind for viewing them.
One of the main causes here are require_once’s and Zend_Loader. The first thing you should do is to strip require_once’s from ZF’s library, as the example in the ZF manual shows. After running sed, there’s a notable difference in the speed.
If you are running APC (you should be), you can enable apc.include_once_override in your php.ini for some extra speed in file including.
In general, reading the Zend Framework performance guide is recommended, though not all of the optimizations mentioned there had any effect on my application. That was probably because the quiz app is relatively simple in terms of ZF interaction.
It should probably be noted, that according to KCachegrind, Zend_Loader was called 94 times! It could be beneficial to combine some of the classes used on every request into a single big include file.
There are some built in features in Doctrine which you can enable to increase performance. These are the query and result caches. The query cache holds compiled DQL queries, and the result cache holds query results.
To learn about the query and result caches, see the Doctrine manual, caching chapter.
You often hear that it’s better to use Doctrine_Query, than the find-methods on Doctrine_Table. Wrong!
It turns out that if you actually need to fetch the whole record, using the find methods is faster than using a Doctrine_Query! This may not be very surprising, as Doctrine_Query objects require the code to parse the DQL snippets. However, it may still be faster to use Doctrine_Query if you have large objects, but only need some of the data.
Changing the hydration mode for some queries to HYDRATE_ARRAY, so that instead of objects Doctrine returns arrays, didn’t field any significant gains. The biggest time consumer in Doctrine queries seemed to be the generation of SQL clauses from DQL.
There are many people who say ZF is slow. While it may be true on some level, it also boasts a much bigger feature set than many frameworks. Despite all this, optimizing ZF apps is pretty simple, even if you just follow the guidelines in the ZF manual.
What comes to Doctrine, the most beneficial way (in terms of performance) to optimize it is to not use it, and work with SQL queries yourself. However, it’s often faster to develop with Doctrine. You can also use heavy page-caching to reduce the need for calling the ORM magics, which would remove most of the penalties incurred.
There’s a good post on page-caching in Padráic Brady’s blog which is worth a read.