带有子菜单的渲染菜单性能严重下降
每当我渲染菜单项时,对于从数据库中找到的每个菜单项,我都会使用它来检查其子菜单。
我的控制器渲染菜单项和递归函数来检测其子菜单如下
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;
}
,MenuItem Mapper 中的函数 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 秒。这一切都在本地主机中。我的递归有什么缺陷吗?我可以采取什么措施来提高代码的性能?
Whenever I render a menu item, for each of the menu item I found from the database, I use it to check its sub-menus.
My Controller rendering the menu item and recursive function to detect its sub-menus are as follows
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;
}
And function getItemsByMenu in MenuItem Mapper
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;
}
}
I have about 4 different types of menu rendered in my app and I am noticing significant performance degradation in the execution. I often get Execution timeouts, the difference between the rendering time with the menus are about 35 sec and without are 22 sec approx. And this all in localhost. Is there any flaw in my recursion? What measure can I take to improve the performance of the code?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我看不到任何可以解释 35 秒执行时间的内容,除非菜单表中有 100,000 个项目,而且根本没有索引。建议:
我假设
getPageDetails
code>正在做另一个数据库理想情况下,您希望在加载菜单项时加载这些详细信息(通过加入页面表),这样您就可以将页面数据数组传递给getPageDetails
而不必这样做对每个项目执行额外的查询。如果这没有带来任何神奇的改进,请尝试启用数据库分析器,以便您可以查看是否是数据库查询的数量或速度造成的。的问题。
I can't see anything in there that would explain 35 second execution time, unless you have 100,000s of items in your menus table with no indexes at all. Suggestions:
Make sure you have an index on the menu items table on:
menu_id, parent, position
(that's one index on three fields, with the fields in that order.I assume
getPageDetails
is doing another database query. Ideally you'd want to load these details when you load the menu items (by joining in the pages table), so you could then just pass the array of page data togetPageDetails
instead of having to do an additional query per item.If that doesn't give any miraculous improvements, try enabling the DB profiler so you can see whether it's volume or speed of the database queries that is causing the issue.
这里明显的问题是从数据库获取菜单的方式。
如果您为每个菜单项发出一个获取其子菜单的请求,那么您很快就会收到大量请求。一个简单的解决方案是实施缓存,但您可以首先尝试改进查询菜单的方式。
映射树的一个很好的替代方法是使用物化路径,而不是引用父项。这意味着您在字段中存储一个字符串,其中包含当前项目的路径(以逗号分隔)。真正的好处是,您可以在路径字段上使用正则表达式仅在一个请求中获得一整棵树:
然后使用一些代码(例如某些递归函数)构建整个导航。
并考虑缓存这类东西
The obvious problem here is the way you fetch your menu from the database.
If for each menu item you do a request to fetch it's submenus, you will quickly end with a lot of requests. An easy solution would be to implement caching, but you could first try to improve the way you query your menu.
A good alternative for mapping trees, instead of referencing the parent item is to use a materialized path. This means that you store in a field a string containing the path to the current item, comma-separated. The real benefit is that you could get a whole tree in only one request using a regexp on the path field :
Then with a little code, like some recursive function you build your whole navigation.
And consider caching this sort of things