【发布时间】:2014-08-15 02:44:33
【问题描述】:
我有一个名为“视频”的实体,附加到它的是由 ManyToOne 和 ManyToMany 关联的其他实体。
我的问题是,正在执行的查询数量对正常流量感到不舒服。例如,我在首页上执行了可变数量的查询,大约有 49 个查询。
正在执行的绝大多数查询是因为我的视频实体的子实体在调用时没有自动初始化。转储时,我看到私有属性“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 从不费心为每个视频获取 Product 数据,因此它为我要求的每个图标创建一个查询,这使我们最多 11 个(最少,ManyToMany 意味着每个视频可以与多个产品相关联)。此页面上还有 3 条视频查询,用于不同的列表,使用 VideoRepository 中的不同方法
这里的问题是,虽然缓存系统将每个主查询的结果数据存储 5 分钟,但它还隐藏了尚未获取产品和其他嵌入式实体。
所以用简单的数学计算,这意味着使用缓存系统只为我节省了 4 个查询,使我的 Doctrine 查询计数达到 45 个。
在使用 getResult 时,是否有一种简单的方法告诉 Doctrine 对所有子实体进行子查询和自动水合?
【问题讨论】:
-
左加入产品数据将导致它在初始查询中加载。您还可以在您的关联(甚至全局)上设置 fetch=eager,但您可能并不想这样做。 doctrine-orm.readthedocs.org/en/latest/reference/…
-
嗯,当我将
products属性设置为Eager时,执行查询时似乎没有缓存结果:\ -
我自己不使用 Doctrine 缓存的东西,所以我无法帮助你。您的标签表明您正在使用 Symfony 2,因此您可以尝试它们的缓存。它相当广泛。并且不要忘记在更改 Doctrine 关联时清除 Symfony 缓存。
标签: php mysql symfony caching doctrine-orm