我正在开发一个具有n级别类别树的产品目录的应用程序。
我有下一个结构:
Category 1
--Category 1.1
----Category 1.1.1
------Product 1.1.1.1
------Product 1.1.1.2
----Product 1.1.1
--Category 1.2
----Product 1.2.1
--Product 1.1
我需要像扁平阵列这样的东西:
Category 1
Category 1.1
Category 1.1.1
Product 1.1.1.1
Product 1.1.1.2
Product 1.1.1
Category 1.2
Product 1.2.1
Product 1.1
但问题是我需要太多查询和太多时间来生成这个(我有700个产品和200个类别或多或少,它需要大约846个查询和2100毫秒来执行它们)。我可以添加更多联接,但执行时间会显着增加。我正在与可翻译实体合作。
任何想法最小化查询数量和执行时间?类别具有自我关系和与产品的关系。
我认为一个选项可以是获取所有类别并制作有序树,然后再次重新制作平面阵列,但我不知道它是否是最佳选择......
提前感谢您的帮助!
编辑: 这是我生成“扁平”数组的功能。
public function generateCategoriesTree($categories, $result = array()) {
$tempResult = array();
if(count($categories)) {
foreach($categories as $k => $v) {
$tempResult[] = $v;
if(count($v->getCategories())) {
$temp = $this->generateCategoriesTree($v->getCategories(), $result);
foreach($temp as $kk => $vv) {
$tempResult[] = $vv;
}
}
}
}
return array_merge($result, $tempResult);
}
但问题不在这里,问题是当我尝试访问树的第二级时,调用方法getcategories时,在数据库中执行查询。
更新
通过这个解决方案,我将查询数量从700减少到100,执行时间从2100ms减少到350ms。我认为现在已经足够了,因为这个动作每小时使用一次。
if ($this->isGranted('ROLE_EMPLOYEE') || $currentUser->isXXXXXXSeller()) {
$XXXXXXCategories = $em->getRepository('CatalogBundle:Category')->getMainCategoriesByBrand(1);
if(is_array($XXXXXXCategories)) {
$categoriesXXXXXX = $this->get('core_tools')->generateCategoriesTree($XXXXXXCategories);
$categories = new ArrayCollection(
array_merge($categories->toArray(), $categoriesXXXXXX)
);
}
}
$categoriesToShow = array();
$products = $em->getRepository('CatalogBundle:Product')->getAllOrderedByPosition();
if(is_array($products) && is_array($categories)) {
foreach($categories as $category) {
$categoriesToShow["c_".$category->getId()] = array(
"category" => $category,
"products" => array(),
);
}
foreach($products as $product) {
if($product->getCategories()) {
foreach($product->getCategories() as $productCategory) {
if(array_key_exists("c_".$productCategory->getCategory()->getId(), $categoriesToShow)) {
$categoriesToShow["c_".$productCategory->getCategory()->getId()]['products'][] = $product;
}
}
}
}
}
答案 0 :(得分:3)
如果目录不经常更改(即:超过每几秒钟) - 然后执行一次艰苦的工作,然后将输出缓存以备即时使用。
目录更改时 - 重建缓存。
答案 1 :(得分:0)
如果你使用MySQL,你可能会考虑使用#34;嵌套集"用于存储类别层次结构的模型。无论您的类别树有多少级别,SELECT的复杂性通常都会保持不变。可以使用Doctrine扩展程序来帮助您进行设置(例如https://github.com/blt04/doctrine2-nestedset)。
如果您使用支持分层查询的DBS,可以考虑使用它们(https://en.wikipedia.org/wiki/Hierarchical_and_recursive_queries_in_SQL)。