Жадная загрузка в Yii2, для тех кто хочет понять что это такое
Используем жадную загрузку в своем приложении. Допустим у нас имеется две таблицы с постами и категориями. У каждого поста возможна одна категория, у категорий 1 или более постов.
Допустим мы скрудили модели, контроллеры, представления по этим таблицам. Заполним список постов. Обратите внимание, в колонке категорий отображаются сами названия категорий, а не id категорий.
Отобразить название категорий можно в представлении: «views/post/index.php» изменив GridView таким образом:
= GridView::widget([
'dataProvider' => $dataProvider,
'filterModel' => $searchModel,
'columns' => [
['class' => 'yii\grid\SerialColumn'],
'id',
[
'attribute' => 'category_id',
'filter' => Category::find()->select(['name', 'id'])->indexBy('id')->column(),
'value' => 'category.name',
],
'name',
'content:ntext',
['class' => 'yii\grid\ActionColumn'],
],
]); ?>
// 'attribute' => 'category_id', к атрибуту category_id, добавляем значение 'value' => 'category.name', где name как раз после с названием категории
// 'filter' => Category::find()->select(['name', 'id'])->indexBy('id')->column(), -- дает фильтрацию по название категорий
// 'value' => 'category.name',
Вот как раз, здесь нам и пригодится «жадная загрузка». Дело в том, что если мы посмотрим sql — запросы нашего приложения.
Мы увидим множество запросов из таблицы category, такого вида
SELECT * FROM `sb_category` WHERE `id`=x
Где x — id из постов — category_id. Если у нас будет выводится на странице 100, 500, 1000 постов, будет и столько же выборок в таблице post. В данном случае, если посмотреть по времени выполнения скрипта, запросы в БД выполняются быстро. Но если мы можем сэкономить ресурсы, почему бы этим не воспользоваться. Для этого создана «жадная загрузка». Жадная загрузка, это загрузка с избыточными данными, как бы с присоединенной таблицей.
В модели app\models\PostSearc, в методе search, добавим жадную загрузку через метод with
public function search($params)
{
$query = Post::find();
public function search($params)
{
$query = Post::find()->with(['category']);
После этого смотрим на результат:
Сейчас мы видим, вместо многочисленных запросов в БД, мы получаем всего 2. Выборку данных из таблиц psot и category.
Метод with собирает все поля category_id из таблицы post, и делает один запрос в БД, извлекая все категории по условию WHERE `id` IN (1, 2, 3, 4, 5). Т.е в where перечисляются все id, которые есть в первой выборке post
SELECT * FROM `sb_post` LIMIT 20
Для того что бы работала фильтрация, сортировка в GridView. Необходимо вместо with (), использовать joinWith ().
joinWith () выполняет жадную загрузку и присоединяет дополнительную таблицу с помощью join и это дает нам возможность добавлять условия, сортировку.
Комментарии (15)
22 июля 2016 в 17:47 (комментарий был изменён)
0↑
↓
Для Ruby On Rails есть gem bullet определяющий N+1 запросы и выдающий стек-трейс где это исправить.
Интересно, подобная реализации для Yii2 присутствует?P.S Загрузите изображения в habrastorage.org
22 июля 2016 в 17:49
–1↑
↓
Не сразу понял, о чем речь. Все же «жадный» — это greedy (например, greedy regex quantifier). Eager — разве что в переносном смысле, вообще это скорее «жаждущий».23 июля 2016 в 00:54
+1↑
↓
Жадная загрузка — это общепринятое понятие, обозначаемое в английском языке как eager loading. И переводится оно именно так. И если перейти к вашему дословному переводу слова eager (вернее, одному из возможных переводов), то человек, испытывающий жажду, пьет с жадностью, отсюда и понятие.23 июля 2016 в 01:14
–1↑
↓
Погуглил. Да, это явно общепринятый перевод, вы правы.
В оправдание скажу, что я, кроме хабра, на русском языке ничего связанного с IT/CS не читаю.
22 июля 2016 в 18:10 (комментарий был изменён)
0↑
↓
У меня на работе VK заблокирован. Почему Вы не выложили картинки на habrastorage? Перезалейте, пожалуйста. Вообще использовать vk как хостинг картинок совершенно неправильно.22 июля 2016 в 18:22
0↑
↓
Извините дорогие читатели. Сейчас исправлю изображения.23 июля 2016 в 00:17
–1↑
↓
Може ленивая, а не жадная?23 июля 2016 в 02:42
0↑
↓
Как раз по умолчанию ленивая, а автор повествует о том, как сделать жадную.23 июля 2016 в 11:48
0↑
↓
Была изначально ленивая, сделали жадную.
23 июля 2016 в 11:48
0↑
↓
Это как раз антонимы.23 июля 2016 в 11:48
+3↑
↓
Извините пожалуйста, но о этом знаком практически каждый человек, хоть немного работающий в yii2.
Статья была бы интересней, если бы вы рассказали о жадной загрузке в подгруженных жадных загрузках. Либо варианты доставать данные через 2–3 загрузки.23 июля 2016 в 12:34
+1↑
↓
На хабре периодически появляются подобные статьи, поражающие своей очевидностью.
23 июля 2016 в 11:49
–1↑
↓
Прост в шоке… Какой чудесный недокументированный метод… А какой прекрасный подход. Спасибо, что сообщили о своей находке. Обязательно возьму на вооружение, а то эти 100500 запросов при моих постоянных выборках для вывода по 500–1000 элементов на страницу уже задрали.23 июля 2016 в 16:08
0↑
↓
Да уж! Учите матчасть.
23 июля 2016 в 16:08
–2↑
↓
Я не знаю Yii, но проще, быстрее и вообще, было сделать в основном запросе сразу сделать сразу выборку названий категорий JOIN-ном или SELECT-вом двух таблиц — не имеет значения. Вы берете ORM и потом героический боретесь с ним и, в данном случае, особенностями виджетов GridView.