Если ваш сайт на Yii2 начинает тормозить при росте данных, скорее всего, проблема в запросах. ActiveQuery — это мощный инструмент, который может превратить медленные выборки в молниеносные. В этой статье разберём, как правильно готовить запросы, чтобы база данных не становилась узким горлышком.
Почему ActiveQuery, а не чистый SQL?
Многие думают: «Зачем эти абстракции, если можно написать SQL руками?» Но ActiveQuery даёт удобство и безопасность. Вы работаете с объектами, а не с строками, и при этом можете строить сложные запросы. Главное — понимать, как он работает под капотом.
ActiveQuery — это класс, который представляет собой запрос к базе. Он умеет ленивую загрузку, жадную загрузку, кэширование и многое другое. Но если использовать его неаккуратно, он сгенерирует чудовищный SQL, который положит сервер.
->createCommand()->rawSql или отладчик Yii.
Жадная загрузка против ленивой: кто кого?
По умолчанию Yii2 использует ленивую загрузку (lazy loading). Это значит, что связанные данные подгружаются только при обращении к ним. Удобно, но может привести к проблеме N+1.
Пример: у вас 100 статей, и вы в цикле выводите автора каждой. Ленивая загрузка сделает 100 дополнительных запросов. Итого 101 запрос вместо одного.
Решение — жадная загрузка (eager loading) через with().
// Плохо: 101 запрос
$articles = Article::find()->all();
foreach ($articles as $article) {
echo $article->author->name;
}
// Хорошо: 2 запроса
$articles = Article::find()->with('author')->all();
foreach ($articles as $article) {
echo $article->author->name;
}
Жадная загрузка сначала выбирает все статьи, а потом одним запросом подтягивает всех авторов. Разница ощутима.
Выбирайте только нужные поля
Когда вы делаете Article::find()->all(), Yii выбирает все поля из таблицы. Если в таблице 50 колонок, а вам нужны только 3, вы тратите память и время на передачу лишних данных.
Используйте select(), чтобы указать конкретные поля.
// Выбираем только id и title
$articles = Article::find()
->select(['id', 'title'])
->all();
Но будьте осторожны: если вы потом обратитесь к полю, которого нет в select, Yii вернёт null. Это может сломать логику.
asArray(), если вам не нужны объекты ActiveRecord. Это экономит память и ускоряет выборку.
Индексы и условия WHERE
ActiveQuery позволяет строить сложные условия, но не забывайте про индексы. Если вы фильтруете по полю, на котором нет индекса, база будет сканировать всю таблицу.
Пример: Article::find()->where(['status' => 1])->all(). Если по status нет индекса, при миллионе записей это будет медленно.
Добавьте индекс в миграции:
$this->createIndex('idx-article-status', 'article', 'status');
Также избегайте функций в WHERE, например WHERE YEAR(created_at) = 2023. Это убивает индекс. Лучше использовать диапазон:
$articles = Article::find()
->where(['>=', 'created_at', '2023-01-01'])
->andWhere(['<', 'created_at', '2024-01-01'])
->all();
Кэширование запросов
Если данные меняются редко, а запрос тяжёлый, используйте кэширование. ActiveQuery умеет кэшировать результаты.
$articles = Article::find()
->where(['status' => 1])
->cache(3600) // кэш на час
->all();
Но помните: кэш нужно сбрасывать при изменении данных. Можно использовать зависимости кэша.
$dependency = new \yii\caching\DbDependency([
'sql' => 'SELECT MAX(updated_at) FROM article'
]);
$articles = Article::find()
->where(['status' => 1])
->cache(3600, $dependency)
->all();
Теперь кэш автоматически сбросится, если любая статья обновится.
Пакетная обработка больших данных
Если вам нужно обработать много записей, не загружайте их все в память. Используйте batch() или each().
// Обрабатываем по 100 записей
foreach (Article::find()->batch(100) as $articles) {
foreach ($articles as $article) {
// что-то делаем
}
}
Это снижает потребление памяти и предотвращает падение при больших выборках.
Сравнение методов оптимизации
| Метод | Когда использовать | Эффект |
|---|---|---|
| with() | Связанные данные в цикле | Убирает N+1 |
| select() | Нужны не все поля | Меньше данных |
| asArray() | Не нужны объекты | Экономия памяти |
| cache() | Редко меняющиеся данные | Снижение нагрузки |
| batch() | Обработка больших выборок | Контроль памяти |
Что в итоге?
ActiveQuery — это не просто удобная обёртка, а инструмент, который при правильном использовании даёт серьёзный прирост производительности. Главные правила: используйте жадную загрузку, выбирайте только нужные поля, не забывайте про индексы, кэшируйте тяжёлые запросы и обрабатывайте данные пакетами.
Начните с малого: проверьте свои запросы на наличие N+1 и добавьте with(). Уверен, вы удивитесь, насколько быстрее станет сайт.
Студия WNDER

