在Symfony2中显示目录太慢

时间:2015-08-17 07:55:39

标签: php symfony

我正在开发一个具有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;
                }
            }
        }
    }
}

2 个答案:

答案 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)。