我正在使用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();
答案 0 :(得分:4)
1)您的EntityRepository::findBy()
方法会执行此操作:
2)您的EntityManager::createQueryBuilder()
方法会执行此操作:
您可以放心地得出结论,选项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)
查询构建器太慢了。
使用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注入。
存储过程最快,但它取决于您的数据库。