Значительное снижение производительности рендеринг меню с подменю - PullRequest
0 голосов
/ 26 сентября 2011

Всякий раз, когда я отображаю элемент меню, для каждого элемента меню, найденного в базе данных, я использую его для проверки его подменю.

Мой контроллер, отображающий пункт меню и рекурсивную функцию для обнаружения его подменю, выглядит следующим образом

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 в 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;
    }
}

В моем приложении отображается около 4 различных типов меню, и я замечаю значительное снижение производительности при выполнении. Я часто получаю тайм-ауты выполнения, разница между временем рендеринга с меню составляет около 35 секунд, а без - около 22 секунд. И это все в localhost. Есть ли недостаток в моей рекурсии? Какие меры я могу предпринять для улучшения производительности кода?

Ответы [ 2 ]

0 голосов
/ 26 сентября 2011

Очевидной проблемой здесь является способ извлечения вашего меню из базы данных.

Если для каждого пункта меню вы делаете запрос на выбор его подменю, вы быстро закончите с много запросов.Простым решением было бы реализовать кэширование, но вы могли бы сначала попытаться улучшить способ запроса меню.

Хорошей альтернативой для отображения деревьев вместо ссылки на родительский элемент является использование материализованной путь .Это означает, что вы храните в поле строку, содержащую путь к текущему элементу, через запятую.Реальное преимущество заключается в том, что вы можете получить целое дерево всего за один запрос, используя регулярное выражение в поле пути:

//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 голосов
/ 26 сентября 2011

Я не вижу там ничего, что объясняло бы 35-секундное время выполнения, если у вас нет 100 000 элементов в таблице меню без индексов вообще. Предложения:

  1. Убедитесь, что у вас есть индекс в таблице пунктов меню: menu_id, parent, position (это один индекс на три поля с полями в таком порядке.

  2. Я полагаю, getPageDetails выполняет другой запрос к базе данных. В идеале вы хотели бы загрузить эти данные при загрузке пунктов меню (путем объединения в таблицу страниц), чтобы затем можно было просто передать массив данных страницы в getPageDetails вместо того, чтобы выполнять дополнительный запрос для каждого элемента.

Если это не дает каких-либо чудесных улучшений, попробуйте включить профилировщик БД, чтобы вы могли видеть, является ли объем или скорость запросов к базе данных причиной проблемы.

...