本文概述
- 1.处理多个实体时避免对象水化
- 2.如果你可以永久引用它, 请不要加载整个实体
- 3.不要从循环中的实体获取引用的值
- 4.使用’update’语句更新多行, 而不是对象持久化
- 5.如果没有必要, 不要只是为了获得一个简单的值而加载整个对象(带有关系)
如今, Symfony开发人员中最普遍使用的是”对象对象关系映射”(ORM), 因为尽管有些人不同意这一点, 但它使开发人员与数据库之间的事情变得非常容易。
你应该已经知道, Doctrine 2在性能方面无法与旧版本的Doctrine 1进行比较, 例如:
-
Doctrine1实现ActiveRecord设计, 而D2实现DataMapper设计-这是最重要的区别。
-
D2需要PHP 5.3或更高版本, 并使用其好处, 例如名称空间。
-
D2分为一组较小的子项目:Doctrine Commons, Doctrine DBAL, Doctrine ORM(用于RDBMS)和Doctrine ODM(用于MongoDB)。
-
D2快得多。
-
D2支持注释。
教义无疑会使php程序员的生活更轻松。
在此处了解更多信息http://stackoverflow.com/questions/4400272/what-are-the-differences-between-doctrine1-and-doctrine2。
但是, 鼓励你(作为开发人员)提供高质量的结果, 应用程序的性能给开发人员和开发人员提供了很多话题, 并学习了一些在symfony2项目中使用学说来优化性能的技巧。
1.处理多个实体时避免对象水化
当你从数据库中检索许多寄存器以仅在视图中显示它们时(例如, 默认的CRUD生成的文件), 你应该考虑不要使用Doctrine的默认对象混合(返回Doctrine_collection对象, 该对象翻译为更多的内存和时间)。通过以下方法提高保湿性能。
而不是检索像Doctrine_collection的对象:
// In the controller
$em = $this->getDoctrine()->getManager();
$repo = $em->getRepository('ourcodeworldBundle:Users');
$query = $repo >createQueryBuilder('a')
->where('a.role LIKE :role')
->setParameter('role', '%ADMIN%');
$results = $query->getQuery()->getResult();// Default hydration
改为申请:
// In the controller
$em = $this->getDoctrine()->getManager();
$repo = $em->getRepository('ourcodeworldBundle:Users');
$query = $repo >createQueryBuilder('a')
->where('a.role LIKE :role')
->setParameter('role', '%ADMIN%');
$results = $query->getQuery()->getArrayResult();// Array hydration
$results = $query->getQuery()->getScalarResult();// Scalar hydration
2.如果你可以永久引用它, 请不要加载整个实体
让我们想象一个实体, 该实体具有从另一个数据库表引用的字段(一个User对象的字段Role具有Role表中的外键), 并且要持久化该用户对象, 你需要setRole($ roleObject)作为Role Entity 。
在那种情况下, 执行额外的find(例如, 用于请求参数的$ id)操作将强制执行不必要的附加数据库语句(这是我们所有人为解决此问题所要做的事情), 如下所示:
仅当你确定数据的来源时(当不经常清除环境缓存时), 才必须使用getReference。
但是有时候, getReference对于以前来说很方便。根据资源ID管理较大的集合(如操作)。这样, 你不必为每个资源都执行SELECT(find())语句。
// In the controller
$em = $this->getDoctrine()->getManager();
$repo = $em->getRepository('ourcodeworldBundle:Users');
$roleId = 2;
$role = $repo->find($roleId);
$user = new User();
$user->setName('Invisible man');
$user->setAge(27);
$user->setRole($role);
$em->persist($user);
$em->flush();
多亏了《教义》的参考代理, 你不必从数据库中检索整个实体, 而只需要将其与另一个实体相关联, 如下所示:
// In the controller
$em = $this->getDoctrine()->getManager();
$roleId = 2;
$user = new User();
$user->setName('Invisible man');
$user->setAge(27);
$user->setRole($em->getReference('ourcodeworldBundle:Users', $roleId));
$em->persist($user);
$em->flush();
3.不要从循环中的实体获取引用的值
让我们想象一个实体, 该实体具有从另一个数据库表引用的字段(一个User对象的字段Role具有Role表中的外键), 并且要持久化该用户对象, 你需要setRole($ roleObject)作为Role Entity 。
我们返回显示给用户的视图, 然后使用如下所示的树枝循环渲染其名称, 角色名称和年龄:
{%for user in collectionUsers %}
<tr>
<td>{{user.name}}</td>
<td>{{user.role.name}}</td>{# Keep in mind that for every user , A QUERY will be executed asking for the name of its role !#}
<td>{{user.age}}</td>
</tr>
{%endfor%}
因此, 当你渲染100个用户时, 你希望通过Join Query的结果和在Array Result中发送collectionUsers, 这将大大提高与以前的测试相比的性能, 因为最终将仅执行1个查询。
$qb = $this->createQueryBuilder('p');
$qb->addSelect('a')
->innerJoin('p.role', 'a');
return $qb->getQuery()->getArrayResult();
4.使用’update’语句更新多行, 而不是对象持久化
当你必须更新多个实体时, 从数据库中检索它们并将其作为ORM实体进行迭代是一种非常糟糕的做法
$em = $this->getDoctrine()->getManager();
$repo = $em->getRepository('ourcodeworldBundle:Posts');
$newCreatedAt = new \DateTime();
$posts = $repo->findAll();
foreach ($posts as $post) {
$post->setCreatedAt($newCreatedAt);
$em->persist($post);
}
$em->flush();
建议改为申请:
$em = $this->getDoctrine()->getManager();
$repo = $em->getRepository('ourcodeworldBundle:Posts');
$newCreatedAt = new \DateTime();
$qb = $repo->createQueryBuilder('p');
$qb->update()
->set('p.createdAt', ':newCreatedAt')
->setParameter('newCreatedAt', $newCreatedAt);
$qb->getQuery()->execute();
5.如果没有必要, 不要只是为了获得一个简单的值而加载整个对象(带有关系)
除非你可以处理标量和数组值, 否则这是防止加载仅占用内存空间的不必要信息的好提示。
$em = $this->getDoctrine()->getManager();
$repo = $em->getRepository('ourcodeworldBundle:Users');
$age = $repo->createQuery(
'SELECT z.age'.
'FROM ourcodeworldBundle:Users z'.
'WHERE z.id = :id'
)
->setParameter('id', 2)
->getSingleScalarResult();
return $age;//Just the number we need !
一些重要的建议:
- 确保你正确创建查询。
- 仅从数据库中加载你真正需要的内容, 然后返回需要水合或对象的对象。
在该学说的网站上, 有一个要点:
强烈建议使用APC之类的字节码缓存。字节码缓存消除了对每个请求解析PHP代码的需求, 并可以大大提高性能。
“如果你在乎性能, 而不使用字节码缓存, 那么你实际上就不在乎性能。请得到一个并开始使用它。” Stas Malyshev, PHP和Zend员工的核心贡献者
最后, 请谨慎将本文应用于你的项目。如果你的项目无法处理非常高的流量, 繁重的查询或具有低规格的项目, 则不必参加所有这些建议。
评论前必须登录!
注册