在getResult上强制瀑布保湿

时间:2014-08-14 17:49:22

标签: php mysql symfony caching doctrine-orm

我有一个名为' Video'的实体,并附加到它,是由ManyToOne和ManyToMany关联的其他实体。

我的问题是,正在执行的查询量正在使用常规流量时感到不舒服。例如,我在首页上执行了可变数量的查询,并且获得了大约49个查询。

正在执行的绝大多数查询都是因为我的Video实体的子实体在调用时没有自动初始化。当倾倒时,我看到一个私有财产" is_initialized"设置为0.在我的模板中调用时,因为它们倾向于报告,然后Doctrine执行查询以获取该数据。

我理解为什么Doctrine这样做,如果没有使用这些数据,为什么要把它放在第一位呢?在大多数情况下,这种行为很好。

但就我而言,我的VideoRepository课程中有一些方法可以获取特定的视频集。所以我在这里使用DQL。作为回应,我决定在DQL中将结果缓存设置为Apc。

这是来自存储库

的相对无害的示例
    /**
     * Get Videos based on recently submitted
     *
     * @param null $limit
     * @param int $page
     * @return array
     */
    public function latest($limit = null, $page = 1)
    {
        $hash = md5(sprintf("%s_%s", $limit, $page));

        $query = $this->getEntityManager()->createQueryBuilder();
        $query->select('v')->from($this->getEntityName(), 'v')
            ->where('v.published = :published')
            ->orderBy('v.datePublished', 'DESC')
            ->setParameter('published', true);

        if($limit) {
            $query->setFirstResult((int)(($page-1) * $limit));
            $query->setMaxResults($limit);
        }

        $resultQuery = $query->getQuery();
        $resultQuery->setResultCacheDriver(new ApcCache())->useResultCache(true, 300, sprintf('results_latest.%s', $hash));

        return $resultQuery->getResult();
    }

因此,在首页(执行49个查询,生产数据开始点击后会有更多内容)中,有10个视频是通过此方法请求的。

每个视频的内部都是一个关联的"产品"实体(ManyToMany)。在每个视频的缩略图显示中,都是一个小产品图标,因此我自然需要从视频实体访问包含产品实体的$product属性。

此时,它正在执行10个以上的查询,因为Doctrine从不打算为每个视频获取产品数据,因此它为我要求的每个图标创建一个查询,这使我们达到11(最小,ManyToMany意味着每个视频可以与多个产品相关联)。在VideoRepository

中使用不同的方法,在此页面上查询了另外3个视频条,用于不同的列表

这里的问题是,虽然缓存系统用于存储每个主查询的结果数据5分钟,但它还存储了尚未获取产品和其他嵌入式实体的情况。

因此,通过简单的数学运算,这意味着使用缓存系统只保存了4个查询,使我的Doctrine查询计数达到了45个。

使用getResult时,是否有一种简单的方法可以告诉Doctrine子查询并自动为所有子实体加水?

1 个答案:

答案 0 :(得分:1)

是的,更改您的查询以选择更多实体,并且学说将需要更少的延迟加载。

$query->select('v', 'sub', 'others')
        ->from($this->getEntityName(), 'v')
        ->leftJoin('v.subtitles','sub')
        ->leftJoin('v.others','others')
        ->where('v.published = :published')
        ->orderBy('v.datePublished', 'DESC')
        ->setParameter('published', true);

这将返回更多数据,并且每次需要字幕或其他实体时,doctrine都不会有连续查询。作为警告,这将返回更多数据,因此请确保此方法可以接受。