【问题标题】:Doctrine2 fetch Count more optimized and faster way Or Zf2 libraryDoctrine2 fetch Count 更优化更快的方式或 Zf2 库
【发布时间】:2014-04-14 15:24:24
【问题描述】:

我正在使用 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();

【问题讨论】:

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


    【解决方案1】:

    比较

    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();
    

    【讨论】:

      【解决方案2】:

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

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

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

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

      【讨论】:

      • 非常感谢...知道这一切让我如释重负
      【解决方案3】:

      查询生成器太慢了。

      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. 使实体的所有关系变得惰性。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-10-01
        • 2011-12-18
        • 2011-11-22
        • 1970-01-01
        • 2016-07-27
        • 2023-01-26
        • 2016-09-01
        相关资源
        最近更新 更多