对于每个想知道symfony2 + doctrine2和性能的人来说,这都是一种Q / A.
我正在编写此Q / A,因为我已经开始围绕SF2 +学说参与一个新项目,我想做一些性能测试。我已经上网但没有找到完整的答案,因此我决定自己制作一个。希望这对某人有用
我们假设我们有两个实体,如下所示
//all ORM declaration here
class Lodging
{
//some declaration here
/**
* @ORM\ManyToOne(targetEntity="Currency")
* @ORM\JoinColumn(name="currency_iso_code", referencedColumnName="iso_code")
*/
protected $currency;
//some methods here
}
//all ORM declaration here
class Currency
{
/**
* @ORM\Id
* @ORM\Column(type="string", length=3)
*/
protected $iso_code;
/**
* @ORM\Column(type="string")
*/
protected $description;
//some methods here
}
现在,您将为Lodging
创建一个实体类型,您可以在其中创建或 - 如果传递给该类型的实体具有一些预取值 - 来编辑Lodging对象(让我们专注于那个案子)。在该表单中,您还需要Currency
的说明,而不仅仅是$iso_code
。
问题:最好使用->findOneById()
doctrine2方法或编写DQL(或使用查询构建器工具)?
为什么呢?
答案 0 :(得分:3)
只有当您遇到使用延迟加载的慢页面时,此答案才有意义。对于更常见的操作(只加载一个实体,加载“静态页面”或缓存的操作等),您可以继续使用doctrine提供的内置函数
好吧,让我们分析一下您可以遵循的一些不同的方法
findOneById()
在控制器中,您选择遵循更多“常用”和“快速”方式进行处理:使用预先存在的findOneById()
方法。精彩。
Lodging
对象,第二个查询当前关联{{1} (延迟加载)和一个获取所有Currency
实体(因为您可以从一种货币更改为其他货币)Currency
public function findLodgingById($id)
{
$lodging = null;
$q = $this->createQueryBuilder('lodging')
->select('lodging')
->where('lodging.id = :id')
->setParameter('id', $id)
->getQuery();
$lodging_array = $q->getResult(); //will not fetch a single object but array
if ($lodging_array) {
$lodging = reset($lodging_array);
}
return $lodging;
}
public function findLodgingById($id)
{
$lodging = null;
$q = $this->createQueryBuilder('lodging')
->select('lodging')
->leftJoin('lodging.currency', 'currency')
->where('lodging.id = :id')
->setParameter('id', $id)
->getQuery();
$lodging_array = $q->getResult(); //will not fetch a single object but array
if ($lodging_array) {
$lodging = reset($lodging_array);
}
return $lodging;
}
实体,但似乎忽略了该指令。答案是我们不是 选择 货币实体,因此doctrine2将再次使用延迟加载工具。currency
public function findLodgingById($id)
{
$lodging = null;
$q = $this->createQueryBuilder('lodging')
->select('lodging', 'currency')
->leftJoin('lodging.currency', 'currency')
->where('lodging.id = :id')
->setParameter('id', $id)
->getQuery();
$lodging_array = $q->getResult(); //will not fetch a single object but array
if ($lodging_array) {
$lodging = reset($lodging_array);
}
return $lodging;
}
与其他解决方案相比,public function findLodgingById($id)
{
$lodging = null;
$q = $this->createQueryBuilder('lodging')
->select('lodging')
->where('lodging.id = :id')
->setParameter('id', $id)
->getQuery();
$q->setHint(Query::HINT_FORCE_PARTIAL_LOAD, true);
$lodging_array = $q->getResult(); //will not fetch a single object but array
if ($lodging_array) {
$lodging = reset($lodging_array);
}
return $lodging;
}
代码行似乎可以节省时间和内存。
此解决方案不允许您更改关联的($q->setHint(Query::HINT_FORCE_PARTIAL_LOAD, true);
)实体,因为它将与Currency
结果似乎对页面加载时间有好处(内存使用当然不会改变)虽然性能似乎只是“稍微好一点”,但你不应该只关注结果:这里我们采取的一个示例只是一个简单的代码片段,只有一个延迟加载操作:想一个实体(或者,最糟糕的是,很多实体,比如带有相关注释的博客文章)会对每个获取和管理的实体进行错误的(*)延迟加载:对于单个页面,您甚至可以达到50-70查询(当然,在这种情况下,由于“单个”查询,您可以轻松地注意到性能优势)
(*)为什么我说错了?因为如果您可以将对象的提取逻辑迁移到其他地方,或者您已经知道所需的实体/属性,那么您的内容不是动态,您可以在使用之前了解它们,延迟加载不仅无用而且有害。
相反,如果你不能在“编写代码时”知道你需要什么属性或实体,当然延迟加载可以节省你浪费在无用的对象/关联上的记忆(和时间)。
最好“丢失”使用“内置”查询的写DQL查询(似乎甚至是愚蠢的)几分钟。此外,您应该使用数组(而不是对象)进行只读操作(无法修改的列表元素)更改Query::HINT_FORCE_PARTIAL_LOAD, true
方法调用,如下所示:getResult()
。这将更改“默认”值(getResult(Doctrine\ORM\Query::HYDRATE_ARRAY);
)
答案 1 :(得分:0)
在看到问题之前,过早的优化似乎要担心它。
写出最快的东西,在这种情况下,通常会是$em->findOneById($id)
样式。然后使用valgrind寻找瓶颈。
考虑编写所有自定义DQL所花费的时间,可以通过在应用程序中的其他位置修复更大的问题来提高整体性能。