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



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

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

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

$qb = $this->getEntityManager()->createQueryBuilder();
$qb->select('count(p)')
->from('UserEntityMembers', 'p')
->where('p.id = '.$id)
->andWhere('p.status = 1');
$membersCnt = $qb->getQuery()->getSingleScalarResult();

比较

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

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

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

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

您可以有把握地得出结论,选项 2 比选项 1 有效得多:

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

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

安全评论

切勿将值连接到查询中! 当这些值是(派生自)用户输入时,这可能会使您容易受到 SQL 注入攻击。

此外,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 UserEntityMembers p WHERE p.id = :id AND p.status = :status';
$q = $this->getEntityManager()->createQuery($dql);
$q->setParameters(array('id' => $id, 'status' => 1));
$membersCnt = $q->getSingleScalarResult();

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

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

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

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

查询生成器太慢了。

  1. 使用 DQL 可以更快地选择 。

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

    您需要设置参数来防止SQL注入。

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

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

相关内容

  • 没有找到相关文章