所以我在我的一些项目中使用 QueryBuilder,但其他项目我需要创建 RAW SQL 查询以提高性能,因为我有超过一百万行与它们的关系......
我发现 QueryBuilder 的糟糕之处在于,当您有关系时,它会创建多个查询,例如,我有一个从Product
到Image
的OneToMany
关系,并且在反转端有一个ManyToOne
。
我的查询具有分页,因此仅限于LIMIT 10 OFFSET 0
和更多。我的Image
实体大约有 270 万行,这就是为什么我使用分页,执行这个简单的查询,它获取Image i
加Product p
,因为我需要p.title
我最终为我的 1 张图像提供 1 个查询,Image
的每个Product
有 10 个查询。
这是不需要的,只需 2 个查询即可完成,一个用于Image
,一个用于Product
,使用fetch="EAGER"
这就是我得到的。但是我需要fetch="EXTRA_LAZY"
放在Product
映射中,否则我将再次收到 11 个查询。
只有 10 张图像并不难,但是当用户过滤 500 张图像时,响应时间会越来越长......这就是为什么我最终做了 RAW 查询,最佳性能,没有额外的查询(只有 1 个包含所有内容的查询),但无法像 QueryBuilder 那样处理对象,无法访问 twig 内部image.product.title
以获取标题,相反,我需要做SELECT p.title AS product_title
并调用image.product_title
等
所以我需要知道为什么 QueryBuilder 在阅读时如此糟糕,但在持久化对象时却如此出色(简单、快速、干净......),以及我如何使用 QueryBuilder 处理大型数据库而不会降低性能,也不会获得大量额外的不需要的查询。
一个示例查询,是这个
$qb = $this->createQueryBuilder('i');
$qb->innerJoin('i.product', 'p');
$qb->where('i.X = Y');
return $qb->getQuery()->getResult()
使用 $qb->select('i, p');
似乎只使用一个查询,它是可运行的 raw 有一个 INNER JOIN(这实际上是它在没有 $qb->select()
的情况下工作的方式),但性能仍然低于执行 RAW SQL 查询...对于 10.000 行查询,RAW SQL = 500MS,使用 QB 为 1,100 MS。我知道我不会在使用 10.000 行,但有机会......
问题仍然是一样的,除了对象操作之外,还有什么优点和缺点,RAW SQL已经消失了。以及何时使用LAZY或EAGER 以及为什么,或者为什么/何时不需要它们。
所有这些都可能一劳永逸地结束我的开发团队中的讨论。因为我是QB爱好者。
你有没有做过这样的事情:
SELECT i FROM AcmeBundle:Image i JOIN i.product p WHERE ...
?
这可以解释许多查询,因为Doctrine
不会保留获取的数据。
做这样的事情告诉Doctrine
实际保留Image
和Product
的获取数据:
SELECT i, p FROM AcmeBundle:Image i JOIN i.product p WHERE ...
然后,您将不需要EAGER
也不需要EAGER_LAZY
.
我可能错过了你问题的重点。如果我有,请纠正我,我也许可以提出其他建议。
编辑:
$qb = $this->createQueryBuilder('i');
$qb->innerJoin('i.product', 'p');
$qb->addSelect('p'); // Very importang, hints Doctrine to preserve fetched Product
$qb->where('i.X = Y');
return $qb->getQuery()->getResult()
或使用PARTIAL
:
$qb = $this->createQueryBuilder('i');
$qb->innerJoin('i.product', 'p');
$qb->select('PARTIAL i.{image_field1, image_field2}', 'PARTIAL p.{product_field1, product_field2}'); // Very importang, hints Doctrine to preserve fetched Product
$qb->where('i.X = Y');
return $qb->getQuery()->getResult()