Question

I moved from an old sever running centOS on a managed hoster to a new one running Ubuntu in AWS.

Post the move I've noticed that the page that loads a list of items is now taking ~10-12 secs to render (sometimes even up to 74secs). This was never noticed on the old server. I used newrelic to look at what was taking so long and found that the sfPHPView->render() was taking 99% of the time. From nerelic there is approximately ~500 calls to the DB to render the page.

The page is a list of ideas, with each idea a row. I use the $idea->getAccounts()->getSlug() ability of Doctrine 1.2. Where accounts is another table linked to the idea as a foreign relation. This is called several times for each idea row. A partial is not currently used to hold the code for each row element.

  1. Is there a performance advantage to using a partial for the row element? (ignoring for now the benefit of code maintability)
  2. What is best practice for referencing data connected via a foreign relation? I'm surprised that a call is made to the DB everytime $idea->getAccounts()->getSlug() is called.
  3. Is there anything obvious in ubuntu that would otherwise be making sfPHPView->render() run slower than centOS?
Was it helpful?

Solution

I'll give you my thought

  • When using a partial for a row element, it's more easy to put it in cache, because you can affine the caching by partial.

  • Because you don't explicit define the relation when making the query, Doctrine won't hydrate all elements with the relation. For this point, you can manually define relations you want to hydrate. Then, your call $idea->getAccounts()->getSlug() won't perform a new query every time.

$q = $this->createQuery();
$q->leftJoin('Idea.Account');
  • No idea for the point 3.

PS: for the point 2, it's very common to have lots of queries in admin gen when you want to display an information from a relation (in the list view). The solution is to define the method to retrieve data:

In your generator.yml:

list:
  table_method: retrieveForBackendList

In the IdeaTable:

public function retrieveForBackendList(Doctrine_Query $q)
{
  $rootAlias = $q->getRootAlias();
  $q->leftJoin($rootAlias . '.Account');

  return $q;
}

OTHER TIPS

Though I would add what else I did to improve the speed of page load in addition to jOk's recommendations.

In addition to the explicit joins I did the following:

  1. Switched to returning a DQL Query object which was then passed to Doctrine's paginator
  2. Changed from using include_partial() to PHP's include() which reduced the object creation time of include_partial()
  3. Hydrate the data from the DB as an array instead of an object
  4. Removed some foreach loops by doing more leftJoins in the DB
  5. Used result & query caching to reduce the number of DB calls
  6. Used view caching to reduce PHP template generation time

Interestingly, by doing 1 to 4 it made 5 and 6 more effective and easier to implement. I think there is something to be said for improving your code before jumping in with caching.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top