Doctrine2 fetch Count 更优化更快的方式 或者 Zf2 库

Dee*_*yal 3 orm doctrine doctrine-query doctrine-orm zend-framework2

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

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

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

或者

$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();
Run Code Online (Sandbox Code Playgroud)

Jas*_*wer 6

比较

1)你的EntityRepository::findBy()方法将做到这一点:

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

2)你的EntityManager::createQueryBuilder()方法将做到这一点:

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

您可以肯定地得出结论,选项 2 远比选项 1 有效:

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

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

安全评论

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

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

换句话说,替换这个:

->where('p.id = '.$id)
->andWhere('p.status = 1')
Run Code Online (Sandbox Code Playgroud)

有了这个:

->where('p.id = :id')
->andWhere('p.status = :status')
->setParameters(array('id' => $id, 'status' => 1))
Run Code Online (Sandbox Code Playgroud)

或者:

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

此外

对于此特定查询,无需使用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();
Run Code Online (Sandbox Code Playgroud)