2011-09-26 30 views
0

每当我呈现一个菜单项,我从数据库找到的每个菜单项,我用它来检查其子菜单。大量的性能下降呈现菜单子菜单

我的控制器渲染菜单项和递归函数来检测它的子菜单中菜单项映射如下

public function renderAction() 
{ 
    $menu = $this -> _request -> getParam('menu'); 
    $itemArray = $this -> getSubItems($menu); 
    $container = new Zend_Navigation($itemArray); 
    $this -> view -> navigation() -> setContainer($container);   
} 

private function getSubItems($menu, $parent = 0) { 
    $mapperMenuItem = new Apanel_Model_Mapper_MenuItem(); 
    $menuItems = $mapperMenuItem -> getItemsByMenu($menu, $parent); 
    if(count($menuItems) > 0) { 
     $itemArray = array(); 
     foreach($menuItems as $item) { 
      $label = $item -> label; 
      $uri = $this -> getSubItemUrl($item);    
      $subItems = $this -> getSubItems($menu, $item -> id);   
      if(count($subItems)) {    
       $tArray['pages'] = $subItems; 
      } 
      $tArray['label'] = $label; 
      $tArray['uri'] = $uri; 
      $itemArray[] = $tArray; 
      unset($tArray); 
     } 
     if(count($itemArray)) { 
      return $itemArray; 
     } else { 
      return null; 
     }  
    } else { 
     return null; 
    }  
} 

    private function getSubItemUrl($item) { 

     if(!empty($item -> link)) { 
      $uri = $item -> link;      
     } else { 
      $pageMapper = new Apanel_Model_Mapper_Page(); 

      $details = $pageMapper -> getPageDetails($item -> page_id);    
      $pageClass = "CMS_Content_Item_".ucwords($details['namespace']); 
      $page = new $pageClass($item -> page_id); 
      $title = str_replace(" ", "-", strtolower($details['name'])); 
      $uri = $this -> view -> url(array(
       "namespace" => $details['namespace'], 
       "title"  => $title 
      ),'page-view'); 
     } 
     return $uri;    
    } 

和功能getItemsByMenu

public function getItemsByMenu($menuId, $parent = 0) { 
    $select = $this -> getDbTable() -> select();   
    $select -> where("menu_id = ?", $menuId) 
      -> where("parent = ?", $parent) 
      -> order("position"); 
    $items = $this -> getDbTable() -> fetchAll($select); 
    if($items -> count() > 0) { 
     return $items; 
    } else { 
     return null; 
    } 
} 

我有4种不同类型的菜单渲染在我的应用程序中,我注意到执行过程中显着的性能下降。我经常得到执行超时,渲染时间和菜单之间的差异大约是35秒,而没有大约22秒。这一切都在localhost。递归中是否有缺陷?我可以采取什么措施来提高代码的性能?

+0

你能张贴getItemsByMenu和getSubItemUrl的代码? –

+0

@TimFountain,我已更新我的问题。 – Starx

回答

0

我看不出有什么解释35秒的执行时间,除非您的菜单表中有100,000个项目,根本没有索引。建议:

  1. 请确保您有关于菜单项表的索引:menu_id, parent, position(这三个领域的一个指标,按该顺序领域

  2. 我认为getPageDetails正在做另一个数据库查询理想情况下,当您加载菜单项(通过加入页表)时,您希望加载这些详细信息,因此您可以将页面数据数组传递至getPageDetails,而不必为每个项目执行额外的查询。

如果这不会带来任何奇迹般的改进,请尝试启用数据库分析器,以便查看导致问题的数据库查询的数据量或速度。

+0

按照你的第一点。如果你指的是这个,我确实有一个索引作为该表中的主键。关于第二点,如何通过联接执行自定义查询? – Starx

+0

如果你只有一个主键索引,那么你肯定需要根据我的第一个建议添加一个额外的索引 - 这应该会有很大的帮助。至于自定义连接,你可以在select对象上使用'joinInner'来引入一个额外的表格,尽管Zend_Db_Table可能有点时髦,所以先试试索引。 –

+0

我以前没有使用过索引....你能否用一个可能的例子来阐述你的第一个例子。我在每个字段上都设置了索引类型为“index”的索引。 – Starx

0

这里显而易见的问题是您从数据库中获取菜单的方式。

如果对于每个菜单项,您都会请求获取它的子菜单,您将很快以结束很多的请求。一个简单的解决方案是实现缓存,但您可以先尝试改进查询菜单的方式。

映射树,而不是引用父项的一个很好的替代方法是使用materialized path。这意味着您在字段中存储一个字符串,其中包含当前项目的路径,以逗号分隔。真正的好处是,你可以在只有一个要求使用路径字段一个正则表达式得到一整棵树:

//get the whole tree of menu 1 
SELECT * FROM menuitems WHERE path REGEXP '^1' ORDER BY path; 

| ID | Name   | Path | 
| 1 | Hardware  | "1" | 
| 2 | Printers  | "1,1" | 
| 3 | Laser printers | "1,1,1"| 
| 4 | Ink printers | "1,1,2"| 
| 5 | Screens  | "1,2" | 
| 6 | Flat Screens | "1,2,1"| 
| 7 | Touch Screens | "1,2,1"| 

然后用很少的代码,像一些递归函数你建立你的整个导航。

而且考虑缓存这种事情

+0

您提供的链接不包含任何文章。 – Starx

+0

对不起,唯一与任何技术无关的资源。在这里你[对mongoDb有一个解释](http://www.mongodb.org/display/DOCS/Trees+in+MongoDB#TreesinMongoDB-MaterializedPaths%28FullPathinEachNode%29),但它的原理是一样的。区别在于路径与行ID无关 –