7. Symfony2 performance issues and improvements
Symfony book Performance
- Use a Byte Code Cache (e.g. APC)
- Use Composer's Class Map Functionality
- Caching the Autoloader with APC
- Use Bootstrap Files
8. Symfony2 performance issues and improvements
Expensive service construction
- Be careful with listeners for kernel.request, kernel.
controller, kernel.view and kernel.response events.
- Don't perform any work in the service constructor
- Minimize deep layers of dependencies
- Minimize injecting services into listeners
- Use lazy services
9. Symfony2 performance issues and improvements
kernel.request event issues
- Avoid calling a database or external services in listeners
- Don’t forget check request type and skip listener run for sub-requests
- Avoid excessive usage of Internal Subrequests. Every sub-request will
go through the HttpKernel event lifecycle.
use SymfonyComponentHttpKernelEventGetResponseEvent;
// ...
public function onKernelRequest(GetResponseEvent $event)
{
if (!$event->isMasterRequest()) {
// don't do anything if it's not the master request
return;
}
// ...
}
12. Symfony2 performance issues and improvements
Doctrine best practice
- Constrain relationships as much as possible. Avoid bidirectional
associations if possible
- Avoid composite keys
- Use lifecycle events judiciously
-Make $em->clear() in batches
$batchSize = 20;
for ($i = 1; $i <= 10000; ++$i) {
$user = new User;
$user->setStatus('user');
$user->setUsername('user' . $i);
$user->setName('Mr.Smith-' . $i);
$em->persist($user);
if (($i % $batchSize) === 0) {
$em->flush();
$em->clear(); // Detaches all objects from Doctrine!
}
}
$em->flush(); //Persist objects that did not make up an entire batch
$em->clear();
14. Symfony2 performance issues and improvements
Enable doctrine cache
You can use your own service:
doctrine:
orm:
metadata_cache_driver: apc
result_cache_driver: apc
query_cache_driver: apc
doctrine:
orm:
metadata_cache_driver:
type: service
id: acme.demo.doctrine.cache.mycache
// ...
15. Symfony2 performance issues and improvements
Custom caching service
<?php
namespace AcmeDemoBundleDoctrineCache;
use DoctrineCommonCacheCacheProvider
class MyCache extends CacheProvider
{
protected function doFetch($id) {}
protected function doContains($id) {}
protected function doSave($id, $data, $lifeTime = 0) {}
protected function doDelete($id) {}
protected function doFlush() {}
protected function doGetStats() {}
}
16. Symfony2 performance issues and improvements
Caching in action
/**
* Get all articles with best rank
* @return array
*/
public function findBestArticles()
{
$query = $this->createQueryBuilder('article')
->select('article.title, article.description, article.published')
->where('article:rank = :rank')
->orderBy('article.published')
->setParameter('rank', 5)
->getQuery();
$query->useResultCache(
true,
3600,
__METHOD__ . serialize($query->getParameters())
);
$query->useQueryCache(true);
return $query->getArrayResult();
}
18. Symfony2 performance issues and improvements
Beware of lazy loading
Beware of lazy loading when querying entities with associations
{% for article in articles %}
<article>
<h2>{{ article.title }}</h2>
<p>Author: {{ article.author.firstName }} {{ article.author.lastName }}</p>
<p>{{ article.text }}</p>
</article>
{% endfor %}
19. Symfony2 performance issues and improvements
Beware of lazy loading
Beware of lazy loading when querying entities with associations
Apparent solution:
{% for article in articles %}
<article>
<h2>{{ article.title }}</h2>
<p>Author: {{ article.author.firstName }} {{ article.author.lastName }}</p>
<p>{{ article.text }}</p>
</article>
{% endfor %}
$articles = $this->getDoctrine()->getRepository('AcmeDemoBundle:Article')->findAll();
20. Symfony2 performance issues and improvements
Beware of lazy loading
Right solution:
// src/Acme/DemoBundle/Entity/Repository/ArticleRepository
public function findAllWithAuthors()
{
$qb = $this->createQueryBuilder('article');
$qb->addSelect('author')
->innerJoin('article.author', 'author');
return $qb->getQuery()->getResult();
}
21. Symfony2 performance issues and improvements
Don't use hydration without needs
Doctrine ORM, like most ORMs, is performing a process called Hydration
when converting database results into objects.
With hydration:
Without hydration
$articles = $this->createQueryBuilder('article')->getQuery()->getResult();
$articles = $this->createQueryBuilder('article')->getQuery()->getResult(Query::HYDRATE_ARRAY);
$articles = $this->createQueryBuilder('article')->getQuery()->getArrayResult();
22. Symfony2 performance issues and improvements
Use Reference Proxies
With get author query into DB:
Without query for getting author:
$author = $this->getDoctrine()
->getManagerForClass('AcmeDemoBundle:Article')
->getRepository('AcmeDemoBundle:Article')->find($authorId);
$article = new Article();
$article->setAuthor($author);
$em = $this->getDoctrine()->getManagerForClass('AcmeDemoBundle:Article');
$article = new Article();
$article->setAuthor($em->getReference('AcmeDemoBundle:Author', $authorId));
23. Symfony2 performance issues and improvements
Assets
- Merging and minifying assets with Assetic (YUI compressor)
- CSS at top javascript at bottom
- use sprites for images
- encode small images into base64
- run image optimizations on your images