Symfony 2 OneToMany性能优化

时间:2016-03-24 14:45:26

标签: php symfony doctrine-orm

我在网站上发现了性能问题。 我有一个实体" Cart"与oneToMany关系。当我在一个提供大约2000个查询的视图中调用getter方法时。然后页面的性能下降非常强烈。

我的实体购物车与OneTMany assoc:

class Cart {
    /**
     * @ORM\OneToMany(targetEntity="Comiti\UserBundle\Entity\Subscription", mappedBy="cart")
     */
    protected $subscriptions;
}

我的实体使用ManyToOne assoc订阅:

class Subscription {
    /**
     * @ORM\ManyToOne(targetEntity="Comiti\UserBundle\Entity\Cart",inversedBy="subscriptions")
     * @ORM\JoinColumn(name="cart_id", referencedColumnName="id")
     * @JMS\Exclude()
     */
    protected $cart;
}

我的twig视图调用getSubscriptions()产生大量数据库请求:

{% for subscription in cart.subscriptions %}

我能做些什么才能获得更好的表现?

1 个答案:

答案 0 :(得分:1)

您遇到的问题称为N + 1问题。您正在获取一个具有关联的实体,然后您可以遍历该实体并再次查询。在您的具体示例中,这发生在此循环中,假设您的订阅具有成本:

{% for subscription in cart.subscriptions %}
    {{ subscription.cost }}

鉴于您已经查询过购物车,您尚未加载所有订阅及其属性,而且这些订阅及其属性在循环时发生。要解决这个问题,您应该在购物车上fetch join进行订阅:

// in CartRepository
public function findCartWithSubscriptions($cartId)
{
    $qb = $this->createQueryBuilder('c');
    $qb->leftJoin('c.subscriptions', 's')
    ->where("c = :cart")
    ->setParameter("cart", $cartId);

    return $qb->getQuery()->getResult();
}

这将为您提供一个Cart对象,并将其订阅加载到内存中。