С чего начать оптимизацию производительности PHP-сайта
Оптимизацию PHP-сайта лучше начинать не с переписывания кода, а с замеров. Медленный сайт может тормозить из-за SQL-запросов, тяжёлых изображений, внешних API, отсутствия кэша, неудачной конфигурации PHP-FPM или просто из-за одного неудачного цикла в шаблоне. Без измерений легко потратить день не туда.
Сначала зафиксировать проблему
Нужно понять, что именно считается медленным: главная страница, каталог, админка, импорт, поиск, оформление заказа или конкретный cron. Для разных сценариев будут разные инструменты.
- страницы сайта — смотреть TTFB, общий вес и запросы браузера;
- backend-операции — смотреть логи, SQL и профилирование;
- cron и импорты — замерять время выполнения команды;
- API — отдельно проверять внешние запросы и таймауты.
time php yii some/command
Если проблема проявляется только иногда, стоит посмотреть нагрузку на сервер и медленные запросы в базе. Иногда “сайт тормозит” на самом деле означает, что ночью запускается тяжёлый импорт.
Проверить логи и ошибки
Ошибки тоже могут замедлять сайт. Например, предупреждение PHP в цикле, повторяющееся тысячу раз, создаёт лишнюю запись в лог и расходует ресурсы. Поэтому перед оптимизацией стоит открыть логи.
tail -n 200 runtime/logs/app.log
tail -n 200 /var/log/nginx/error.log
Если в логах много одинаковых сообщений, сначала убирают их. Это не всегда даёт большой прирост, но снижает шум и помогает видеть настоящие проблемы.
SQL-запросы: частая причина тормозов
В Yii2 удобно случайно получить N+1: список товаров загружается одним запросом, а для каждой строки отдельно тянутся категории, цены или остатки. На десяти товарах это незаметно, на тысяче — уже проблема.
$products = Product::find()
->with(['category', 'prices'])
->where(['status' => 'A'])
->all();
with() не является универсальным лекарством, но часто помогает убрать десятки повторяющихся запросов. Для тяжёлых списков стоит смотреть фактический SQL и план выполнения.
EXPLAIN SELECT * FROM products WHERE status = 'A' ORDER BY created_at DESC;
Если фильтр используется постоянно, возможно, нужен индекс. Но индекс добавляют под конкретный запрос, а не “на всякий случай”. Лишние индексы замедляют запись и занимают место.
Кэшировать не всё подряд
Кэш полезен, когда данные часто читаются и редко меняются. Но кэширование случайного куска кода может только усложнить поддержку. Перед добавлением кэша нужно понять срок жизни данных и момент сброса.
$key = ['active-categories'];
$categories = Yii::$app->cache->get($key);
if ($categories === false) {
$categories = Category::find()
->where(['status' => 'A'])
->orderBy(['sort_order' => SORT_ASC])
->asArray()
->all();
Yii::$app->cache->set($key, $categories, 3600);
}
Для Yii2 отдельно полезно помнить про кэш схемы таблиц. На рабочих проектах это снижает лишние обращения к базе.
'db' => [
'class' => 'yii\db\Connection',
'enableSchemaCache' => true,
'schemaCacheDuration' => 3600,
'schemaCache' => 'cache',
],
Изображения и фронтенд
Иногда PHP уже отвечает быстро, но страница всё равно кажется медленной из-за изображений. Баннер в несколько мегабайт, неподходящий формат или отсутствие lazy loading легко портят впечатление.
- проверить вес главных изображений;
- использовать реальные размеры, а не уменьшение огромной картинки через CSS;
- включить lazy loading для изображений ниже первого экрана;
- убрать лишние сторонние скрипты;
- проверить кеширование статических файлов.
<img src="/uploads/product.webp" width="600" height="400" loading="lazy" alt="">
Composer и автозагрузка
На production-сервере зависимости обычно устанавливают без dev-пакетов и с оптимизированной автозагрузкой. Это не решит проблему плохих запросов, но является нормальной базовой настройкой.
composer install --no-dev --prefer-dist --optimize-autoloader
Если проект старый, перед обновлением Composer стоит быть осторожнее. Иногда одна новая версия пакета тянет за собой несовместимость. Для рабочих серверов лучше использовать lock-файл.
PHP-FPM и opcache
Без opcache PHP каждый раз заново читает и компилирует файлы. Для нормального production-окружения opcache должен быть включён.
php -i | grep opcache.enable
Пример базовых настроек:
opcache.enable=1
opcache.memory_consumption=128
opcache.max_accelerated_files=20000
opcache.validate_timestamps=1
opcache.revalidate_freq=2
На некоторых проектах validate_timestamps отключают и сбрасывают opcache при деплое. Это быстрее, но требует дисциплины. Если забыть сброс, сервер может продолжить выполнять старый код.
Рабочий порядок оптимизации
- Зафиксировать медленный сценарий.
- Измерить время ответа и посмотреть логи.
- Проверить количество SQL-запросов.
- Найти N+1 и медленные запросы.
- Проверить кэширование повторяющихся данных.
- Проверить вес изображений и сторонние скрипты.
- Проверить Composer, opcache и PHP-FPM.
- Повторить замер после каждой правки.
Главное правило простое: одна правка — один повторный замер. Если менять всё сразу, потом сложно понять, что действительно помогло, а что просто совпало по времени.
Комментарии (0)
Пока нет комментариев. Будьте первым!