Форум программистов, компьютерный форум, киберфорум
long399
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
По возможности буду размещать интересные записи в своем блоге

Как жадная загрузка в Yii2 помогла мне оптимизировать рендер тяжелой страницы

Запись от long399 размещена 12.10.2023 в 10:00
Показов 1559 Комментарии 0
Метки php, xhprof, yii2

Столкнулся на работе с одним разделом сайта, в котором выводится несколько огромнейших таблиц. Использовать пагинацию там нельзя, так как данный раздел проверяется Рособрнадзором (выполняется автоматический мониторинг специальных тегов разметки), и все данные должны быть отображены на одной странице. Этих данных очень много, количество запросов к БД огромное. Имеется кеширование контента страницы, но несмотря на это, все равно очень неприятно ждать рендер страницы, когда время жизни прежнего кеша заканчивается.

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

Образовательные программы имеют связи с дисциплинами.
PHP
1
2
3
4
5
6
7
8
9
10
11
12
/* Program.php class */
 
/**
 * Gets query for [[Discipline]].
 *
 * @return \yii\db\ActiveQuery
 */
public function getDisciplines()
{
    return $this->hasMany(Discipline::class, ['id' => 'id_disc'])
        ->viaTable('program_disciplines', ['id_program' => 'id']);
}
Дисциплины имеют связи с файлами.
PHP
1
2
3
4
5
6
7
8
9
10
11
12
/* Discipline.php class */
 
/**
 * Gets query for [[File]].
 *
 * @return \yii\db\ActiveQuery
 */
public function getFiles()
{
    return $this->hasMany(File::class, ['id' => 'id_file'])
        ->viaTable('discipline_files', ['id_disc' => 'id']);
}
Файлы имеют связи с информацией об электронной цифровой подписи (ЭЦП).
PHP
1
2
3
4
5
6
7
8
9
10
11
/* File.php class */
 
/**
 * Gets query for [[EdsInfo]].
 *
 * @return \yii\db\ActiveQuery
 */
public function getEdsInfo()
{
    return $this->hasOne(EdsInfo::class, ['id_file' => 'id']);
}
И наконец, информация об ЭЦП имеет связи с подписантами.
PHP
1
2
3
4
5
6
7
8
9
10
11
/* EdsInfo.php class */
 
/**
 * Gets query for [[Signatory]].
 *
 * @return \yii\db\ActiveQuery
 */
public function getSignatory()
{
    return $this->hasOne(Signatory::class, ['id' => 'id_signatory']);
}
А примерно так выглядел legacy-код по выводу информации об образовательных программах:
PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
/* controller code */
$programs = Program::findAll();
 
/* view code */
foreach ($programs as $program) {
    foreach ($program->disciplines as $discipline) { // дисциплины
        foreach ($discipline->files as $file) {      // файлы дисциплин
            $edsInfo = $file->edsInfo;               // информация об ЭЦП
            $signatory = $edsInfo->signatory;        // подписант
 
            // вывод информации о дисциплинах образовательной программы и информации об ЭЦП
        }
    }
}
Количество образовательных программ достаточно большое, и вложенные циклы, в которых идет получение связанных данных отрабатывают долго.

Помогла жадная загрузка. Модели образовательных программ я начал получать из БД сразу с необходимыми связями (вложенными) и это значительно ускорило рендер информации в данном разделе.
PHP
1
2
3
4
5
/* controller code */
$programs = Program::find()->with('disciplines.files.edsInfo.signatory')->all()
 
/* view code */
// цикл из примера выше остался без изменений
При таком подходе связанные данные сразу выбираются из БД одним запросом WHERE IN и заносятся в модель, в специальное приватное свойство. Поэтому не потребуется делать множество запросов на их получение в цикле.

Т.е. мы получим из БД образовательные программы, для каждой из которых при этом будет получен список дисциплин. Для дисциплин, в свою очередь, будут получены файлы, для файлов - информация об ЭЦП, для информации об ЭЦП - подписант.

Еще с помощью профилировщика я обнаружил в некоторых моделях неоптимальное использование отношений. Например:
PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/* Program.php class */
 
/**
 * Gets query for [[Direction]].
 *
 * @return \yii\db\ActiveQuery
 */
public function getDirection()
{
    return $this->hasOne(Direction::class, ['id' => 'id_direction']);
}
 
/**
 * Getter for Direction name.
 *
 * @return string
 */
public function getDirectionName()
{
    if ($this->direction) {
        return $this->direction->code.' '.$this->direction->name;
    }
 
    return '';
}
В методе getDirectionName() три раза выполняется получение модели Direction! А ведь её можно получить один раз и использовать как будет угодно.
PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/* Program.php class */
 
/**
 * Getter for Direction name.
 *
 * @return string
 */
public function getDirectionName()
{
    if ($direction = $this->direction) {
        return $direction->code.' '.$direction->name;
    }
 
    return '';
}
В результате всех манипуляций по оптимизации, удалось ускорить рендер данного раздела примерно в 7-9 раз, чему я был приятно удивлен!

При работе пользовался профилировщиком xhprof, который мне здорово помог найти узкие места и стандартной debug-панелью Yii2.
Метки php, xhprof, yii2
Размещено в PHP, Программирование, Yii2
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Всего комментариев 0
Комментарии
 
Новые блоги и статьи
20. Мат мед. Абсентеизм как отдельный тип простоя
anaschu 29.05.2026
Апдейт модели: исправленные баги, абсентеизм и новые механизмы Продолжаю развивать ранее описанную модель рабочего коллектива на AnyLogic. За последние несколько дней был проведён серьёзный. . .
19. здоровье, усталость и психотип работника влияют на производительность предприятия, и наоборот, производительность на здоровье, усталось и психотип
anaschu 28.05.2026
Дискретно-событийная модель рабочего коллектива на AnyLogic: здоровье, выгорание, психотипы и микростимуляция Привет, коллеги. Хочу поделиться итогами нескольких недель работы над симуляционной. . .
"Прокси" для последовательного порта
Eddy_Em 28.05.2026
Эту штуку написал я достаточно давно. Но сейчас вот понадобилось настроить датчик грозы, но при этом не отключать его от "метеодемона". Соответственно, надо запустить этот "прокси": метеодемон будет. . .
Рефакторинг программы уравнивания.
Massaraksh7 26.05.2026
Пример по предыдущей записи в блоге. Но, надо заметить, что, во-первых, там оптимизация не только математики, но и работы с базой данных, и с графами, а во-вторых, это ещё не всё.
Использование TThread в Lazarus для математических вычислений.
Massaraksh7 25.05.2026
Производя рефакторинг своих программ на предмет ускорения их работы, обратил внимание на такой аспект, как сокращение времени матвычислений. Дело в том, что приходится работать с большими матрицами. . .
Модель здравосохранения 18. Чем здоровее работник, тем быстрее выгорает
anaschu 24.05.2026
Имитационная модель корпоративного здравоохранения: что показывает математика Сегодня в модели рабочего коллектива на AnyLogic появились три новые механики — выгорание через накопленную усталость,. . .
Модель здравосохранения 17. Планы на выгорание
anaschu 23.05.2026
Вот конкретная схема реализации: В классе Работник добавить: накопленнаяУсталость — растёт каждый час работы, снижается в перерывы и болезни коэффициентПрезентеизма — снижает продуктивность. . .
Изменение цветов в палитре gif файла aka фавикона
russiannick 23.05.2026
Изменение цветов в палитре gif файла, юзаемого как фавиконка в составе html-файла, помещенная в base64, средствами нативного Java Script, навеянное сном в майский день. Для работы необходим браузер,. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru