【问题标题】:Optimizing a doctrine query to prevent additonal queries优化学说查询以防止附加查询
【发布时间】:2015-07-07 07:36:19
【问题描述】:

我正在构建一个具有更新墙的系统,您只能在其中看到朋友的帖子。 此处的“朋友”由一组两个用户分类,这两个用户各自将彼此添加到他们的朋友列表中。

朋友关联由 Doctrine ManyToMany 关联非常简单地处理,如下所示:

用户.php

//.. other declarations
/**
 * @var ArrayCollection
 * @ORM\ManyToMany(targetEntity="User")
 * @ORM\JoinTable(name="user_friends")
 */
protected $friends;
//.. more unrelated stuff

并在我的查询中获取用户朋友更新(包括他们自己)

UpdateRepository.php

/**
 * Get aggregated list of updates for a user and their friends in chronological order
 * @param User $user
 * @return array
 */
public function getWallUpdates(User $user)
{
    $qb = $this->getEntityManager()->createQueryBuilder('p');
    $qb->select(['p'])->from($this->getEntityName(), 'p');

    $criteria = $qb->expr()->andX();

    // Filter based on Friends
    $friends = [$user];
    foreach($user->getFriends() as $friend) // collect eligible friends
        if($friend->getFriends()->contains($user))
            $friends[] = $friend;

    $criteria->add('p.account IN (:friends)');
    $qb->setParameter('friends', $friends);

    // Filter based on Chronology

    // Filter based on Privacy
    $criteria->add('p.privacy IN (:privacy)');
    $qb->setParameter('privacy', [1, 3]);

    $qb->where($criteria);

    $query = $qb->getQuery();
    $result = $query->getResult();

    return $result;
}

现在这工作了,但问题是if($friend->getFriends()->contains($user)) 行虽然需要知道$user 是否存在于另一个用户的朋友列表中,但会为$user 中的每个人生成一个新查询的朋友列表。

我不介意额外的一两个查询来完成此操作,但我需要在这里谈谈规模。这个应用程序上的一个人可能有数百个朋友。每次加载此页面时,我都无法执行数百个查询(尽管它们可能很小),这可能会很多。

什么是使这更好的可能的最佳解决方案?

现在我可以继续开发,因为它运行正常。

编辑

为了简洁起见,实际上我确实尝试了将EXTRA_LAZY 添加到我的用户实体中的$friends ManyToMany 声明的EXTRA_LAZY 路线。根据文档,如果使用EXTRA_LAZY 获取模式,使用Collection#contains(entity) 不会触发查询。

很明显,这里的问题源于$users 的朋友每个人都需要收集他们的朋友列表才能进行检查。这对我来说很有意义。

还有没有办法将这一切都集中到一个操作中?

【问题讨论】:

    标签: php mysql symfony doctrine-orm doctrine


    【解决方案1】:

    如果您在获取 $user 对象时为用户的朋友和他们的朋友添加连接,那么它应该会切断任何延迟加载。因此,例如,您可以为用户创建一个自定义存储库,如下所示:

    use Doctrine\ORM\EntityRepository;
    
    class UserRepository extends EntityRepository {
    
        public function fetchFriendsOfFriends($userId) {
            return $this->_em->createQuery('SELECT u, f, ff FROM User u '
                    . 'LEFT JOIN u.friends f '
                    . 'LEFT JOIN f.friends ff '
                    . 'WHERE u.id = :userId')
                ->setParameter('userId', $userId)
                ->getSingleResult();
        }
    }
    

    让您的用户实体使用此存储库:

    /**
     * @ORM\Entity(repositoryClass="UserRepository")
     */
    class User {
    ...
    

    然后当你获取你的 $user 时,使用新的 fetch 方法:

    $user = $em->getRepository('User')->fetchFriendsOfFriends($userId);
    

    我尚未对其进行测试,但我认为它会消除延迟加载的需要。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-10-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多