Форум русской поддержки Joomla!® CMS
06.12.2016, 18:09:51 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
   
   Начало   Поиск Joomla 3.0 FAQ Joomla 2.5 FAQ Joomla 1.5 FAQ Правила форума Новости Joomla Реклама Войти Регистрация Помощь  
Страниц: [1]   Вниз
  Добавить закладку  |  Печать  
Автор

Тормозит админка при большом количестве категорий

 (Прочитано 356 раз)
0 Пользователей и 1 Гость смотрят эту тему.
novikov82
Новичок
*

Репутация: +3/-0
Offline Offline

Сообщений: 9


« : 30.09.2015, 01:22:15 »

Попал в довольно гнилую ситуацию: создал в магазине более 3 тысяч категорий, начала феерически тормозить админка на редактировании категорий и товаров.
Беглый анализ дал понять, что затык наступает в функции getTreeAllCategories из модели categories.
В принципе, не мудрено, в функции есть фрагмент:
Код:
                   foreach ($categories as $key => $category){
                        ...
                        while ($category_parent_id || $i < 1000) {
                            foreach ($originalCategories as $originalKey => $originalCategory){
                                ...
                            }
                            $i++;
                        }
Три вложенных цикла, два из них размерностью порядка тысяч, да еще, как я понимаю, глубина вложенности категорий, в общем, несколько десятков миллионов итераций набирается.
Кто как с этим борется? Можно ли улучшить работу магазина в админке, не исправляя авторского кода? Мне в голову ничего пока не пришло - в этой функции ни одного плагина нет.

UPD
Функция buildTreeCategory работает еще ужаснее Sad пришлось пока забить два грубых костыля.
« Последнее редактирование: 30.09.2015, 01:37:26 от novikov82 » Записан
dmitry_stas
Профи
********

Репутация: +798/-4
Offline Offline

Сообщений: 7765



« Ответ #1 : 30.09.2015, 09:57:27 »

Беглый анализ дал понять, что затык наступает в функции getTreeAllCategories из модели categories.
указанный кусок кода выполняется только если isset($filter['text_search']) && !empty($filter['text_search']. соответственно, там далеко не несколько десятков миллионов проходов.

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

Функция buildTreeCategory работает еще ужаснее Sad пришлось пока забить два грубых костыля.
есть тема Что нужно доделать в ЖШ. разработчики ее читают и если просьбы/советы действительно стоящие - то они включают это в апдейты. если вы считаете, что вам есть что предложить в плане оптимизации - предлагайте. уверен, что если будет что слушать, то вы будете услышаны Azn
Записан
novikov82
Новичок
*

Репутация: +3/-0
Offline Offline

Сообщений: 9


« Ответ #2 : 01.10.2015, 10:41:18 »

указанный кусок кода выполняется только если isset($filter['text_search']) && !empty($filter['text_search']. соответственно, там далеко не несколько десятков миллионов проходов.
Да, вы правы, дело не в этом кусочке, а в функции recurseTree, она вызывается в другом месте и используется для построения дерева категорий.
Цитировать
приходилось иметь дело с магазинами, у которых было похожее количество категорий. не видел особых проблем. но вообще конечно согласен с вами, что там есть что оптимизировать.
Думаю, дело не столько в количестве категорий, а в большом уровне вложенности (так уж у меня получилось, что магазин сильно ветвится). Для рекурсии это, очевидно, важно.

И непонятно, как решать проблему. Я пишу о том, что мои костыли грубые - ориентированы под мою задачу, на других задачах не прокатит. Поэтому и разработчикам как-то пока нечего предложить. Придется подумать.
Записан
dmitry_stas
Профи
********

Репутация: +798/-4
Offline Offline

Сообщений: 7765



« Ответ #3 : 01.10.2015, 13:18:56 »

сделайте ради интереса
Код:
echo microtime(true);
до и после вызова recurseTree(), чтобы посмотреть сколько функция выполняется по времени.
думается мне что проблема все таки не в ней...
Записан
novikov82
Новичок
*

Репутация: +3/-0
Offline Offline

Сообщений: 9


« Ответ #4 : 01.10.2015, 19:40:38 »

сделайте ради интереса
Код:
echo microtime(true);
до и после вызова recurseTree(), чтобы посмотреть сколько функция выполняется по времени.
думается мне что проблема все таки не в ней...
Сделал. Дело в ней Sad
Ради эксперимента вставил такую штуку:
Код:
function recurseTree($cat, $level, $all_cats, &$categories, $is_select) {
    $probil = '';
    if($is_select) {
        for ($i = 0; $i < $level; $i++) {
            $probil .= '-- ';
        }
        $cat->name = ($probil . $cat->name);
        $categories[] = JHTML::_('select.option', $cat->category_id, $cat->name,'category_id','name' );
    } else {
        $cat->level = $level;
        $categories[] = $cat;
    }
    foreach ($all_cats as $categ) {
   
        echo "x"; // <--- добавил для проверки

        if($categ->category_parent_id == $cat->category_id) {
            recurseTree($categ, ++$level, $all_cats, $categories, $is_select);
            $level--;
        }
    }
    return $categories;
}
Получил на выходе 7 миллионов иксов. Мне кажется, многовато.
Записан
dmitry_stas
Профи
********

Репутация: +798/-4
Offline Offline

Сообщений: 7765



« Ответ #5 : 01.10.2015, 21:25:12 »

какое время выполнения получили?
Записан
novikov82
Новичок
*

Репутация: +3/-0
Offline Offline

Сообщений: 9


« Ответ #6 : 02.10.2015, 01:25:17 »

какое время выполнения получили?
Пять секунд на локальной машине, на сервере не проверял, но, наверное, чуть меньше.
Но вообще диалог с вами подтолкнул на мысль. Функция recursiveTree написана, по сути, довольно бездарно. В рекурсии стоит цикл по всем категориям, в котором ищутся дочерние категории по идентификатора родителя. И при том количестве категорий, которое обычно бывает в магазинах, это не заметно. А я вот попался...
В общем, поправил ее малой кровью с использованием ассоциативного массива:
Код:
function recurseTree($cat, $level, $all_cats, &$categories, $is_select) {
   static $cat_by_parent = null;
   if(!$cat_by_parent)
   {
$cat_by_parent = array();
foreach ($all_cats as $categ)
{
  if(!$cat_by_parent[$categ->category_parent_id])
$cat_by_parent[$categ->category_parent_id] = array();
  $cat_by_parent[$categ->category_parent_id][] = $categ;
}
    }

    $probil = '';
    if($is_select) {
        for ($i = 0; $i < $level; $i++) {
            $probil .= '-- ';
        }
        $cat->name = ($probil . $cat->name);
        $categories[] = JHTML::_('select.option', $cat->category_id, $cat->name,'category_id','name' );
    } else {
        $cat->level = $level;
        $categories[] = $cat;
    }
if($cat_by_parent)
    if(count($cat_by_parent[$cat->category_id]))
{
foreach ($cat_by_parent[$cat->category_id] as $categ) {
recurseTree($categ, ++$level, $all_cats, $categories, $is_select, $cat_by_parent);
$level--;
}
}
    return $categories;
}

Буду писать в предложения улучшений... Спасибо Azn
Записан
dmitry_stas
Профи
********

Репутация: +798/-4
Offline Offline

Сообщений: 7765



« Ответ #7 : 02.10.2015, 02:02:04 »

угу, норм решение. я бы тоже так писал - исходя из цикла по родительским. по хорошему конечно тут тоже нужны проверки вне циклов, но и так насколько я вижу количество проходов снизилось с n*n до n+n. итого у вас 6 тыс вместо 7 млн Azn
Записан
Страниц: [1]   Вверх
  Добавить закладку  |  Печать  
 
Перейти в:  

Powered by SMF 1.1.21 | SMF © 2006, Simple Machines

Joomlaforum.ru is not affiliated with or endorsed by the Joomla! Project or Open Source Matters.
The Joomla! name and logo is used under a limited license granted by Open Source Matters
the trademark holder in the United States and other countries.

LiveInternet