我想在数据库中获取树的根,它可以正常工作,但问题在于它为500个节点查询数据库500次,有没有办法改进这个?
$query = $this->createQueryBuilder('n')
->where('n.parent IS NULL')
->getQuery();`
实体结构:
Radio\ArchiveBundle\Entity\Category:
type: entity
table: null
repositoryClass: Radio\ArchiveBundle\Repository\CategoryRepository
id:
id:
type: integer
id: true
generator:
strategy: AUTO
fields:
name:
type: string
length: 255
isActive:
type: boolean
nullable: true
oneToMany:
tracks:
targetEntity: Radio\ArchiveBundle\Entity\Track
mappedBy: category
manyToOne:
parent:
targetEntity: Radio\ArchiveBundle\Entity\Category
inversedBy: childrens
fetch: EAGER
oneToMany:
childrens:
targetEntity: Radio\ArchiveBundle\Entity\Category
mappedBy: parent
cascade: [persist, remove]
Symfony2探查器图片:
答案 0 :(得分:1)
正如您所说,您已从数据库中获取了500个根节点。在请求中的某处,访问属性Category::$childrens
。可能在视图中调用Category
上使用该属性的方法(如$node->getChildren()
)。
访问该属性意味着Doctrine需要加载Collection才能获取该节点的子节点。这导致对每个根节点的查询。因此,您还有500个额外的查询。
如果您需要访问子节点,在查询根节点时立即获取它们是明智的:
SELECT rt, chld FROM Category rt LEFT JOIN rt.childrens chld WHERE rt.parent IS NULL
这样,根节点的直接子节点与根节点本身一起被水合。您将查询数量从501减少到只有1。
PS:复数形式的“孩子”是“孩子”(不是“孩子”)。
恕我直言,可以通过切换到Nested Set model来改进类别树的结构。虽然在向树中插入新节点时性能稍差,但更新和选择树变得更加便宜。
例如:使用您现在使用的父/子模型获取整个树,每个级别的深度需要大约1个查询(或者每个级别需要1个JOIN,但这仅在已知最大深度时才有效)。使用嵌套集模型,您只需一个查询即可获取整个树(无论深度如何)。当深度增加时,这将大大提高性能。
查看Tree behavior库的Doctrine Extensions,您可以使用它轻松实现嵌套集模型。还有一个Symfony 2 bundle来集成该库。
只需将其添加到Composer并按照the instructions。
composer.phar require stof/doctrine-extensions-bundle
答案 1 :(得分:0)
您的父实体被热切地获取并且自己有一个引用。
manyToOne:
parent:
targetEntity: Radio\ArchiveBundle\Entity\Category
inversedBy: childrens
fetch: EAGER
因为它是字段parent
和children
的自引用。
在获取类别时,它也会获取children
(如您所料)。但是也会获取这些连接实体的父实体(当它们存在时)。导致额外的查询。这种情况一直持续到所有父母都被遍历为止。