On a tous connu ça : on livre une feature qui marche nickel en dev avec 10 lignes en base de données, et boum... en production, avec 50 000 entrées, le serveur s'écroule. Dans 90% des cas sur Symfony, le coupable n'est pas PHP, mais la façon dont on utilise Doctrine.
Voici 5 techniques que j'applique systématiquement sur mes projets pour garder des temps de réponse sous les 200ms.
1. Tuez le problème N+1 (Eager vs Lazy Loading)
C'est l'erreur du débutant absolu. Vous bouclez sur une liste d'articles et pour chacun, vous appelez $article->getAuthor()->getName(). Résultat ? Doctrine fait 1 requête pour les articles, puis 100 requêtes pour récupérer les 100 auteurs.
La solution : Utilisez les jointures explicites dans votre Repository.
$qb = $this->createQueryBuilder('a')
->leftJoin('a.author', 'u')
->addSelect('u') // C'est cette ligne qui fait la magie !
->getQuery();
2. L'hydratation en tableau (Array Hydration)
Transformer des données brutes SQL en de magnifiques objets PHP (l'hydratation) coûte très cher en CPU et en RAM. Si vous faites une requête juste pour afficher une liste en lecture seule (comme un tableau de bord), vous n'avez pas besoin d'objets complets.
$results = $query->getResult(Query::HYDRATE_ARRAY);
Rien que ça, ça peut diviser la consommation mémoire par 4.
3. Les requêtes partielles (Partial Objects)
Pourquoi faire un `SELECT *` quand vous n'avez besoin que du titre et de l'ID ? Attention, utilisez cette technique uniquement en lecture, car sauvegarder un objet partiel peut vider les champs non chargés en base.
$qb->select('PARTIAL a.{id, title}')
4. Le cache de requêtes et de résultats
Doctrine possède plusieurs niveaux de cache (Query Cache, Result Cache, Metadata Cache). Si une requête complexe renvoie des données qui changent peu (ex: les catégories de votre blog), mettez le résultat en cache !
$query->enableResultCache(3600, 'my_categories_cache');
5. Pensez à vos index SQL !
C'est bête, mais Doctrine ne fait pas de miracles si votre base de données n'est pas optimisée. Si vous filtrez souvent par status ou created_at, ajoutez des index sur ces colonnes directement dans vos entités via l'attribut #[ORM\Index].
En conclusion : Ne faites pas confiance aveuglément à la magie de l'ORM. Ouvrez toujours le Web Profiler de Symfony, regardez l'onglet Doctrine, et chassez les requêtes dupliquées !