Медленные запросы MySQL могут парализовать ваше веб-приложение. В этом руководстве рассматриваются индексация, оптимизация запросов, проектирование таблиц и методы кэширования, которые помогут ускорить работу вашей базы данных в 10 раз.
10 методов оптимизации производительности MySQL, которые должен знать каждый PHP-разработчик
Медленный запрос к базе данных может замедлить работу всего вашего PHP-приложения. Даже запрос, выполняющийся 500 мс, при запуске 100 раз за одну загрузку страницы добавляет 50 секунд времени ожидания. Я собрал 10 наиболее эффективных методов оптимизации MySQL, которые помогли мне ускорить реальные проекты.
- Правильно используйте индексы Индексы — это самый важный элемент оптимизации. Добавляйте индексы для колонок, используемых в WHERE, JOIN и ORDER BY:
-- Check existing indexes SHOW INDEX FROM users; -- Add index to frequently searched column ALTER TABLE users ADD INDEX idx_email (email); -- Composite index for multiple columns ALTER TABLE orders ADD INDEX idx_user_date (user_id, created_at);
- Используйте EXPLAIN для анализа запросов Всегда используйте EXPLAIN, чтобы понять, как MySQL выполняет ваш запрос:
EXPLAIN SELECT * FROM orders WHERE user_id = 5 AND status = 'pending';
Обращайте внимание на:
type=ALL → полное сканирование таблицы (ПЛОХО)
type=ref или type=range → используется индекс (ХОРОШО)
- Выбирайте только то, что вам нужно
// BAD - fetches all columns
$users = $db->query("SELECT * FROM users WHERE active = 1")->fetchAll();
// GOOD - fetch only needed columns
$users = $db->query("SELECT id, name, email FROM users WHERE active = 1")->fetchAll();
- Решите проблему N+1 запросов
// BAD: N+1 queries
$users = $db->query("SELECT * FROM users")->fetchAll();
foreach ($users as $user) {
$posts = $db->query("SELECT * FROM posts WHERE user_id = {$user['id']}")->fetchAll();
}
// GOOD: Single JOIN query
$results = $db->query("
SELECT u.id, u.name, p.title
FROM users u
LEFT JOIN posts p ON p.user_id = u.id
")->fetchAll();
- Всегда используйте пагинацию для больших выборок
-- Page 1 (20 results) SELECT * FROM products WHERE category_id = 5 ORDER BY created_at DESC LIMIT 20 OFFSET 0; -- For very large tables, use cursor pagination SELECT * FROM products WHERE id > :last_id ORDER BY id ASC LIMIT 20;
- Избегайте использования функций на индексируемых колонках
-- BAD: function prevents index usage SELECT * FROM orders WHERE YEAR(created_at) = 2026; -- GOOD: range query uses index SELECT * FROM orders WHERE created_at >= '2026-01-01' AND created_at < '2027-01-01';
- Используйте подходящие типы данных
CREATE TABLE products ( id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY, name VARCHAR(255) NOT NULL, price DECIMAL(10,2) NOT NULL, -- not FLOAT for money is_active TINYINT(1) DEFAULT 1, -- not VARCHAR for booleans description TEXT -- only TEXT when needed );
- Оптимизируйте JOIN-запросы
-- Ensure JOIN columns are indexed ALTER TABLE orders ADD INDEX idx_customer_id (customer_id); -- Prefer INNER JOIN over LEFT JOIN when possible SELECT o.id, c.name FROM orders o INNER JOIN customers c ON c.id = o.customer_id WHERE o.status = 'pending';
- Кэшируйте результаты запросов в PHP
function getCachedQuery($db, $key, $sql, $params = [], $ttl = 300) {
$cacheFile = sys_get_temp_dir() . '/db_' . md5($key) . '.cache';
if (file_exists($cacheFile) && (time() - filemtime($cacheFile)) < $ttl) {
return unserialize(file_get_contents($cacheFile));
}
$stmt = $db->prepare($sql);
$stmt->execute($params);
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
file_put_contents($cacheFile, serialize($result));
return $result;
}
- Отслеживайте медленные запросы
-- Enable slow query log SET GLOBAL slow_query_log = 'ON'; SET GLOBAL long_query_time = 1; SET GLOBAL slow_query_log_file = '/var/log/mysql/slow.log';
Быстрый чек-лист
[ ] Добавьте индексы для колонок в WHERE, JOIN, ORDER BY
[ ] Запустите EXPLAIN для медленных запросов
[ ] Замените SELECT * на конкретные колонки
[ ] Исправьте проблему N+1 запросов с помощью JOIN-ов
[ ] Добавьте LIMIT ко всем запросам
[ ] Используйте диапазоны вместо функций на индексируемых колонках
[ ] Используйте правильные типы данных
[ ] Кэшируйте повторяющиеся запросы
Комментарии (0)
Пока нет комментариев — будьте первым.