使用Symfony2和Doctrine增强数据库处理的5条简单技巧

本文概述

  • 1.处理多个实体时避免对象水化
  • 2.如果你可以永久引用它, 请不要加载整个实体
  • 3.不要从循环中的实体获取引用的值
  • 4.使用’ update’ 语句更新多行, 而不是对象持久化
  • 5.如果没有必要, 不要只是为了获得一个简单的值而加载整个对象(带有关系)
【使用Symfony2和Doctrine增强数据库处理的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员工的核心贡献者
最后, 请谨慎将本文应用于你的项目。如果你的项目无法处理非常高的流量, 繁重的查询或具有低规格的项目, 则不必参加所有这些建议。

    推荐阅读