Doctrine2提取计数更优化和更快的方式或Zf2库

时间:2014-03-11 06:59:27

标签: orm doctrine-orm zend-framework2 doctrine doctrine-query

我正在使用Doctrine2 and Zf2,现在当我需要获取count行时,我有以下两种方法来获取它。但我担心的是更优化和更快的方式,因为将来行将超过50k。任何建议或任何其他方式来获取计数?是否有任何函数可以与findBy ???

一起使用

或者我应该使用普通的Zf2数据库来获取计数。我刚刚发现当数据很大时,ORM不是首选获取结果。如有任何帮助,将不胜感激

$members = $this->getEntityManager()->getRepository('User\Entity\Members')->findBy(array('id' => $id, 'status' => '1'));
$membersCnt = sizeof($members);

$qb = $this->getEntityManager()->createQueryBuilder();
$qb->select('count(p)')
   ->from('User\Entity\Members', 'p')
   ->where('p.id = '.$id)
   ->andWhere('p.status = 1');

$membersCnt = $qb->getQuery()->getSingleScalarResult();

3 个答案:

答案 0 :(得分:4)

比较

1)您的EntityRepository::findBy()方法会执行此操作:

  • 在数据库中查询符合条件的行。数据库将返回完整的行。
  • 然后将数据库结果转换(水合)为完整的PHP对象(实体)。

2)您的EntityManager::createQueryBuilder()方法会执行此操作:

  • 在数据库中查询符合条件的行数。数据库将返回一个简单的数字(实际上是一个表示数字的字符串)。
  • 然后将数据库结果从字符串转换为PHP整数。

您可以放心地得出结论,选项2比选项1更有效:

  • 数据库可以优化查询计数,可能使查询更快(花费更少的时间)。
  • 从数据库返回的数据少得多。
  • 没有实体被水合(只有一个简单的字符串到整数投射)。

总而言之,将使用更少的处理能力和更少的内存。

安全评论

从不将值连接到查询中! 当这些值来自(来自)用户输入时,这会使您容易受到SQL injection攻击。

此外,Doctrine2无法使用预准备的语句/参数绑定,当经常使用相同的查询时(有或没有不同的参数),这会导致性能损失。

换句话说,替换它:

->where('p.id = '.$id)
->andWhere('p.status = 1')

用这个:

->where('p.id = :id')
->andWhere('p.status = :status')
->setParameters(array('id' => $id, 'status' => 1))

或:

->where($qb->expr()->andX(
    $qb->expr()->eq('p.id', ':id'),
    $qb->expr()->eq('p.status', ':status')
)
->setParameters(array('id' => $id, 'status' => 1))

另外

对于这个特定的查询,不需要使用QueryBuilder,你可以直接使用DQL:

$dql = 'SELECT COUNT(p) FROM User\Entity\Members p WHERE p.id = :id AND p.status = :status';
$q = $this->getEntityManager()->createQuery($dql);
$q->setParameters(array('id' => $id, 'status' => 1));

$membersCnt = $q->getSingleScalarResult();

答案 1 :(得分:1)

你应该完全转到计数的dql版本。

使用第一种方法,您将水合(从db结果集转换为对象)每个行作为单个对象并将它们放在一个数组上,然后计算该数组中的项目数量。如果唯一的目标是知道结果集中元素的数量,那将完全浪费内存和周期。

使用第二种方法,dql将被优雅地转换为SELECT COUNT(*)Blah blah blah 普通的SQL语句,将直接从db中检索计数。

关于ORM的评论不是首选,何时检索数据是巨大的,在大批量处理中,您应该对查询进行分页以同时检索数据,以避免内存覆盖,但在这种情况下,您只是检索一个数字,即总数,因此该规则不适用。

答案 2 :(得分:1)

查询构建器太慢了。

  1. 使用DQL进行更快速的选择。

    $query =  $this->getEntityManager()->createQuery("SELECT count(m) FROM User\Entity\Members m WHERE m.status = 1 AND m.id = :id ");
    $query->setParameter(':id', $id);
    

    您需要setParameter来防止SQL注入。

  2. 存储过程最快,但它取决于您的数据库。

  3. 使实体的所有关系变得懒散。