Как включить журнал медленных запросов в MySQL и MariaDB
Журнал медленных запросов — это встроенная диагностическая функция MySQL и MariaDB, которая записывает каждый SQL-оператор, время выполнения которого превышает настраиваемый порог. Он фиксирует продолжительность выполнения запроса, время блокировки, количество проверенных строк, количество отправленных строк и полный текст SQL — предоставляя администраторам баз данных и разработчикам точный файловый журнал аудита каждого запроса, снижающего производительность приложения.
Его включение — одно из наиболее эффективных действий при настройке производительности базы данных. В отличие от универсальных инструментов мониторинга, журнал медленных запросов точно определяет операторы, ответственные за задержки, что делает его незаменимым для оптимизации индексов, реструктуризации запросов и планирования ресурсов на любом сервере — от однопользовательской среды VPS Hosting до многоузлового выделенного кластера баз данных.
Почему журнал медленных запросов важнее базового мониторинга
Большинство команд обращаются к EXPLAIN или SHOW PROCESSLIST реактивно, после того как пользователи сообщают о замедлении работы. Журнал медленных запросов работает проактивно: он накапливает данные за часы или дни реального трафика, фиксируя периодически возникающие проблемы, которые никогда не появляются в окне ручной проверки.
Ключевые операционные преимущества включают:
- Изоляция узких мест — позволяет отличить полное сканирование таблиц, ограниченное CPU, от проблем конкуренции блокировок с помощью соотношений
Query_timeиLock_time - Анализ пробелов в индексах — флаг
log_queries_not_using_indexesвыявляет каждый запрос, выполняющий полное сканирование, независимо от его фактического времени выполнения - Обнаружение регрессий — сравнение снимков журнала до и после развёртывания показывает, привёл ли новый код к появлению более медленных шаблонов запросов
- Доказательная база для планирования ресурсов — значения
Rows_examined, на порядки превышающиеRows_sent, указывают на отсутствующие или неправильно используемые индексы, которые усугубляются под нагрузкой
MySQL и MariaDB: сравнение функций журнала медленных запросов
Оба движка используют одну и ту же базовую инфраструктуру журнала медленных запросов, унаследованную от MySQL 5.1, однако MariaDB расширила её несколькими существенными способами.
| Функция | MySQL 8.0+ | MariaDB 10.6+ |
|---|
| — | — | — |
|---|
| Базовое ведение журнала медленных запросов | Да | Да |
|---|
| Гранулярность `long_query_time` | Микросекунды | Микросекунды |
|---|
| `log_queries_not_using_indexes` | Да | Да |
|---|
| `log_slow_admin_statements` | Да | Да |
|---|
| `log_slow_slave_statements` | Да | Да (также реплика) |
|---|
| `min_examined_row_limit` | Да | Да |
|---|
| `log_slow_verbosity` (расширенная статистика) | Нет | Да (план запроса, explain) |
|---|
| `log_slow_rate_limit` (выборка) | Нет | Да |
|---|
| `log_slow_filter` (по типу запроса) | Нет | Да |
|---|
| `slow_query_log_always_write_time` | Нет | Да |
|---|
| Совместимость с `pt-query-digest` | Полная | Полная |
|---|
| Формат вывода JSON | Да (8.0.14+) | Нет (использует текст) |
|---|
Параметры log_slow_verbosity и log_slow_rate_limit в MariaDB особенно ценны в высоконагруженных производственных средах, где само по себе ведение журнала каждого медленного запроса может стать источником снижения производительности.
Шаг 1: Найдите файл конфигурации
MySQL и MariaDB считывают конфигурацию из разных путей по умолчанию в зависимости от дистрибутива и метода установки.
MySQL:
/etc/my.cnf (RPM-based: RHEL, CentOS, AlmaLinux, Rocky Linux)
/etc/mysql/my.cnf (Debian/Ubuntu)
/etc/mysql/mysql.conf.d/mysqld.cnf (Ubuntu с пакетом mysql-server)
MariaDB:
/etc/my.cnf.d/server.cnf (RPM-based)
/etc/mysql/mariadb.conf.d/50-server.cnf (Debian/Ubuntu)
/etc/mysql/mariadb.cnf (более старые макеты Debian)
Если вы не уверены, какой файл активен, запросите информацию у запущенного процесса:
mysqld --verbose --help 2>/dev/null | grep -A1 "Default options"
Это выводит точный упорядоченный список файлов, которые демон читает при запуске, включая все директории !includedir.
Откройте основной файл конфигурации в предпочитаемом редакторе:
sudo nano /etc/my.cnf
Шаг 2: Добавьте директивы журнала медленных запросов в [mysqld]
Все параметры журнала медленных запросов относятся к разделу [mysqld]. Если раздел не существует, создайте его в начале файла.
[mysqld]
# Core slow query log settings
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow-query.log
long_query_time = 1
# Log queries that skip index usage entirely
log_queries_not_using_indexes = 1
# Avoid flooding the log with index warnings on low-traffic tables
min_examined_row_limit = 100
# Log slow administrative statements (ALTER TABLE, OPTIMIZE TABLE, etc.)
log_slow_admin_statements = 1
Описание параметров:
slow_query_log = 1 — активирует функцию; установите 0 для отключения без удаления блока
slow_query_log_file — абсолютный путь к файлу журнала; пользователь процесса MySQL/MariaDB (mysql) должен иметь права на запись в родительский каталог
long_query_time = 1 — порог в секундах, принимает десятичные значения (например, 0.5 для 500 мс); значение по умолчанию 10 секунд почти всегда слишком мягкое для веб-приложений
log_queries_not_using_indexes — записывает запросы с полным сканированием независимо от long_query_time; используйте в сочетании с min_examined_row_limit для подавления шума от небольших таблиц
min_examined_row_limit — запрос должен проверить не менее указанного количества строк, чтобы попасть в журнал при использовании log_queries_not_using_indexes; предотвращает засорение журнала тривиальными поисками по одной строке
log_slow_admin_statements — фиксирует операции на уровне схемы, блокирующие таблицы, которые часто упускаются из виду как источники задержек
Специфичные для MariaDB дополнения, которые стоит включить в производственной среде:
# MariaDB only — extended per-query statistics in the log
log_slow_verbosity = query_plan,explain
# MariaDB only — log only 1 in every N qualifying queries (rate limiting)
log_slow_rate_limit = 10
log_slow_verbosity = query_plan,explain добавляет план выполнения оптимизатора непосредственно в каждую запись журнала, устраняя необходимость повторного запуска EXPLAIN вручную — что значительно экономит время при диагностике запросов, которые появляются только при производственных шаблонах нагрузки.
Шаг 3: Создайте файл журнала и установите права доступа
Если целевой каталог не существует, создайте его и назначьте владельца перед перезапуском службы. Пропуск этого шага — одна из наиболее распространённых причин, по которой журнал медленных запросов молча не активируется.
sudo mkdir -p /var/log/mysql
sudo touch /var/log/mysql/slow-query.log
sudo chown mysql:mysql /var/log/mysql/slow-query.log
sudo chmod 640 /var/log/mysql/slow-query.log
На системах с принудительным применением SELinux (RHEL, CentOS, AlmaLinux) необходимо также правильно установить контекст файла:
sudo semanage fcontext -a -t mysqld_log_t "/var/log/mysql(/.*)?"
sudo restorecon -Rv /var/log/mysql
Если не установить правильный контекст SELinux, демон успешно запустится, но молча пропустит запись в файл журнала — неприятный крайний случай, который не производит очевидных ошибок в /var/log/messages.
Шаг 4: Перезапустите службу базы данных
Примените изменения конфигурации, перезапустив службу. В дистрибутивах на основе systemd (стандарт на любом современном Linux-сервере):
# MySQL
sudo systemctl restart mysqld
# MariaDB
sudo systemctl restart mariadb
На более старых системах на основе init.d:
# MySQL
sudo service mysqld restart
# MariaDB
sudo service mariadb restart
После перезапуска убедитесь, что служба запустилась корректно:
sudo systemctl status mysqld # or mariadb
sudo journalctl -u mysqld -n 50 --no-pager
Любая ошибка конфигурации в my.cnf предотвратит запуск и отобразится в выводе журнала.
Шаг 5: Включите журнал медленных запросов во время выполнения (без перезапуска)
Для производственных серверов, где перезапуск нежелателен, MySQL и MariaDB поддерживают динамическое включение журнала медленных запросов через SET GLOBAL. Изменения, внесённые таким образом, вступают в силу немедленно, но не сохраняются после перезапуска службы, если они также не записаны в my.cnf.
SET GLOBAL slow_query_log = 'ON';
SET GLOBAL slow_query_log_file = '/var/log/mysql/slow-query.log';
SET GLOBAL long_query_time = 1;
SET GLOBAL log_queries_not_using_indexes = 1;
SET GLOBAL min_examined_row_limit = 100;
Это правильный подход для экстренной диагностики на работающей системе — включите его, соберите 15–30-минутный образец в период пиковой нагрузки, затем отключите, не затрагивая файл конфигурации и не перезапуская демон.
Шаг 6: Проверьте конфигурацию
Подключитесь к клиенту MySQL или MariaDB:
mysql -u root -p
Затем выполните поиск по таблице системных переменных:
SHOW VARIABLES LIKE '%slow_query%';
SHOW VARIABLES LIKE 'long_query_time';
SHOW VARIABLES LIKE 'log_queries_not_using_indexes';
Ожидаемый вывод для корректно настроенного экземпляра:
+-------------------------------+-------------------------------+
| Variable_name | Value |
+-------------------------------+-------------------------------+
| slow_query_log | ON |
| slow_query_log_file | /var/log/mysql/slow-query.log |
+-------------------------------+-------------------------------+
+-----------------+-------+
| Variable_name | Value |
+-----------------+-------+
| long_query_time | 1.000 |
+-----------------+-------+
+-------------------------------+-------+
| Variable_name | Value |
+-------------------------------+-------+
| log_queries_not_using_indexes | ON |
+-------------------------------+-------+
Вы также можете подтвердить, что в журнал ведётся запись, проверив счётчик медленных запросов:
SHOW GLOBAL STATUS LIKE 'Slow_queries';
Этот счётчик увеличивается каждый раз, когда запрос превышает long_query_time, независимо от того, активно ли ведение журнала в файл — это полезно для подтверждения того, что медленные запросы действительно происходят, прежде чем тратить время на анализ пустого файла журнала.
Шаг 7: Чтение и интерпретация необработанного журнала
Используйте tail для мониторинга журнала в реальном времени во время нагрузочного теста или в период пиковой нагрузки:
sudo tail -f /var/log/mysql/slow-query.log
Типичная запись журнала выглядит следующим образом:
# Time: 2024-10-11T12:45:23.489187Z
# User@Host: app_user[app_user] @ 10.0.1.45 [] Id: 1042
# Query_time: 4.561529 Lock_time: 0.000115 Rows_sent: 1 Rows_examined: 847293
# Bytes_sent: 512
SET timestamp=1697030723;
SELECT * FROM orders WHERE customer_email = 'user@example.com' ORDER BY created_at DESC;
Что означает каждое поле:
Query_time — общее время выполнения по настенным часам в секундах
Lock_time — время ожидания получения блокировок таблиц или строк; высокое соотношение Lock_time к Query_time указывает на конкуренцию, а не на отсутствующий индекс
Rows_sent — строки, возвращённые клиенту
Rows_examined — строки, которые механизм хранения просканировал для получения результата; соотношение Rows_examined / Rows_sent выше 100:1 является явным признаком отсутствующего или плохо избирательного индекса
Bytes_sent — присутствует в MariaDB с расширенной детализацией; полезно для выявления запросов, возвращающих излишне большие наборы результатов
В приведённом примере запрос проверил 847 293 строки, чтобы вернуть 1 строку. Добавление индекса на customer_email сократит Rows_examined приблизительно до 1, уменьшив время выполнения с 4,5 секунды до субмиллисекундного.
Шаг 8: Анализ журнала с помощью mysqldumpslow и pt-query-digest
Чтение необработанного файла журнала непрактично в больших масштабах. Два инструмента агрегируют и ранжируют медленные запросы по общему влиянию.
Использование mysqldumpslow (входит в комплект MySQL/MariaDB)
# Top 10 queries by total execution time
sudo mysqldumpslow -s t -t 10 /var/log/mysql/slow-query.log
# Top 10 queries by average execution time
sudo mysqldumpslow -s at -t 10 /var/log/mysql/slow-query.log
# Top 10 queries by rows examined
sudo mysqldumpslow -s r -t 10 /var/log/mysql/slow-query.log
mysqldumpslow нормализует параметры запросов (заменяя литеральные значения на N или S), чтобы структурно идентичные запросы с разными значениями параметров группировались вместе — это необходимо для выявления часто встречающихся шаблонов.
Использование pt-query-digest (Percona Toolkit — рекомендуется для производственной среды)
# Install Percona Toolkit (Debian/Ubuntu)
sudo apt-get install percona-toolkit
# Install Percona Toolkit (RHEL/CentOS/AlmaLinux)
sudo yum install percona-toolkit
# Generate a full digest report
sudo pt-query-digest /var/log/mysql/slow-query.log
# Show only the top 5 queries by total time
sudo pt-query-digest --limit 5 /var/log/mysql/slow-query.log
# Output to a file for later review
sudo pt-query-digest /var/log/mysql/slow-query.log > /tmp/slow_query_report.txt
pt-query-digest формирует ранжированный отчёт, показывающий сигнатуру каждого запроса, общее время выполнения, среднее время, количество вызовов и процентильное распределение. Этот инструмент значительно мощнее mysqldumpslow и является стандартным инструментом, используемым профессиональными администраторами баз данных для анализа журналов медленных запросов.
Шаг 9: Настройте ротацию журналов с помощью logrotate
Без ротации журнал медленных запросов растёт бесконечно. На загруженном сервере с long_query_time, установленным на 1 секунду, файл может достигнуть нескольких гигабайт в течение нескольких дней.
Создайте специальную конфигурацию logrotate:
sudo nano /etc/logrotate.d/mysql-slow
/var/log/mysql/slow-query.log {
daily
rotate 14
missingok
notifempty
compress
delaycompress
sharedscripts
postrotate
/usr/bin/mysqladmin flush-logs 2>/dev/null || true
endscript
}
Пояснение ключевых директив:
rotate 14 — сохраняет 14 дней сжатых архивов; настройте в соответствии с вашим дисковым бюджетом и требованиями к аудиту
compress / delaycompress — сжимает ротированные файлы в gzip, но откладывает сжатие на один цикл, чтобы избежать сжатия файла, который демон может ещё использовать
postrotate — запускает mysqladmin flush-logs после ротации, что сигнализирует демону закрыть текущий дескриптор файла журнала и открыть новый; без этого MySQL/MariaDB продолжает записывать в переименованный файл до следующего перезапуска
Выполните принудительную ротацию вручную для проверки конфигурации:
sudo logrotate -f /etc/logrotate.d/mysql-slow
Шаг 10: Отключите журнал медленных запросов, когда он больше не нужен
Непрерывное ведение журнала медленных запросов с низким порогом (например, 0,5 секунды) на высоконагруженном сервере создаёт ощутимые накладные расходы на I/O. Отключите его после сбора достаточного количества данных:
Через файл конфигурации (постоянно):
[mysqld]
slow_query_log = 0
Затем перезапустите службу:
sudo systemctl restart mysqld # or mariadb
Через переменную времени выполнения (немедленно, непостоянно):
SET GLOBAL slow_query_log = 'OFF';
Метод времени выполнения предпочтителен в производственные часы — он вступает в силу за миллисекунды без какого-либо простоя.
Дополнительно: использование performance_schema в качестве дополнения
Журнал медленных запросов фиксирует запросы, превышающие временной порог. Таблица performance_schema events_statements_summary_by_digest фиксирует агрегированную статистику для каждого отдельного шаблона запроса, независимо от времени выполнения. Совместное использование обоих инструментов даёт полную картину.
SELECT
DIGEST_TEXT,
COUNT_STAR,
ROUND(SUM_TIMER_WAIT / 1e12, 3) AS total_time_sec,
ROUND(AVG_TIMER_WAIT / 1e12, 6) AS avg_time_sec,
SUM_ROWS_EXAMINED,
SUM_ROWS_SENT
FROM performance_schema.events_statements_summary_by_digest
ORDER BY SUM_TIMER_WAIT DESC
LIMIT 10;
Этот запрос выявляет 10 наиболее ресурсоёмких шаблонов запросов за всю историю операторов — включая быстрые запросы, которые выполняются миллионы раз и в совокупности доминируют по времени CPU, что журнал медленных запросов никогда не зафиксирует.
Особенности хостинговой среды
Оптимальный порог long_query_time во многом зависит от роли сервера и профиля ресурсов:
Среды общего хостинга — как правило, нет прямого доступа к my.cnf; используйте SET GLOBAL, если хостинг-провайдер предоставляет привилегию SUPER или SYSTEM_VARIABLES_ADMIN, или запросите доступ к журналу медленных запросов через панель управления
Среды VPS — полный root-доступ означает полный контроль над всеми параметрами конфигурации; установка VPS с cPanel предоставляет доступ к настройкам журнала медленных запросов через редактор конфигурации MySQL в WHM, который записывает непосредственно в my.cnflong_query_time на уровне 0.1 секунд и использования log_slow_rate_limit (MariaDB) или выборки на уровне приложения для контроля объёма журналаЕсли ваш стек приложений включает веб-интерфейс, управляемый через панель управления VPS, сопоставление временных меток журнала медленных запросов с временными метками журнала HTTP-доступа вашего приложения является эффективным методом отслеживания задержек базы данных до конкретных пользовательских запросов.
Практическая матрица решений: выбор правильного порога
| Среда | Рекомендуемый `long_query_time` | `log_queries_not_using_indexes` | Примечания |
|---|
| — | — | — | — |
|---|
| Разработка / тестирование | 0,1 – 0,5 с | ВКЛ | Раннее обнаружение регрессий; объём журнала приемлем |
|---|
| Производственная среда с низкой нагрузкой | 1,0 с | ВКЛ с `min_examined_row_limit = 500` | Сбалансированное покрытие без избыточной нагрузки на I/O |
|---|
| Производственная среда с высокой нагрузкой | 0,5 – 1,0 с | ВКЛ с `log_slow_rate_limit = 10` (MariaDB) | Ограничение частоты для управления дисковым I/O |
|---|
| OLAP / сервер отчётности | 5,0 – 10,0 с | ВЫКЛ | Длительные запросы ожидаемы; фокус на выбросах |
|---|
| Общий хостинг (ограниченный доступ) | 2,0 с (по умолчанию провайдера) | Зависит от провайдера | Используйте `performance_schema` как альтернативу |
|---|
Технический контрольный список и ключевые выводы
Перед завершением расследования медленных запросов проверьте каждый из следующих пунктов:
- Раздел
[mysqld]вmy.cnfсодержитslow_query_log = 1, допустимый путьslow_query_log_fileиlong_query_time, соответствующий вашему профилю трафика - Файл журнала и его родительский каталог принадлежат системному пользователю
mysqlс правами на запись; на системах с SELinux контекст файла установлен какmysqld_log_t
SHOW VARIABLES LIKE '%slow_query%' подтверждает slow_query_log = ON и правильный путь к файлу после перезапуска службы
SHOW GLOBAL STATUS LIKE 'Slow_queries' показывает ненулевой и увеличивающийся счётчик, подтверждая, что соответствующие запросы действительно происходят
log_queries_not_using_indexes включён и сопряжён с min_examined_row_limit для предотвращения засорения журнала тривиальными поисками по одной строке
log_slow_admin_statements включён для фиксации ALTER TABLE, OPTIMIZE TABLE и аналогичных DDL-операций, которые являются распространёнными источниками неожиданных блокировок таблиц
Конфигурация logrotate настроена с хуком postrotate, вызывающим mysqladmin flush-logspt-query-digest или mysqldumpslow для агрегирования журнала и определили 3–5 наиболее ресурсоёмких запросов по общему времени выполненияEXPLAIN (или EXPLAIN ANALYZE в MySQL 8.0+) и добавлены соответствующие индексы или реструктурирована логика запросаlong_query_time повышен после завершения цикла оптимизации для минимизации текущих накладных расходов на I/OЧасто задаваемые вопросы
Влияет ли включение журнала медленных запросов на производительность базы данных?
При пороге 1 секунда и выше при типичной производственной нагрузке накладные расходы незначительны — обычно менее 1% от общего времени выполнения запросов. Накладные расходы становятся ощутимыми только при установке long_query_time ниже 0,1 секунды или при включении log_queries_not_using_indexes в схеме с множеством небольших неиндексированных таблиц. Используйте log_slow_rate_limit (MariaDB) или повысьте min_examined_row_limit для снижения этого эффекта.
Можно ли включить журнал медленных запросов без перезапуска MySQL или MariaDB?
Да. Используйте SET GLOBAL slow_query_log = 'ON' и SET GLOBAL long_query_time = 1 из любого сеанса клиента MySQL с привилегией SUPER или SYSTEM_VARIABLES_ADMIN. Изменение вступает в силу немедленно. Запишите те же значения в my.cnf, чтобы сделать их постоянными после перезапуска.
В чём разница между Query_time и Lock_time в журнале медленных запросов?
Query_time — это общее прошедшее время по настенным часам с момента получения сервером запроса до отправки последней строки клиенту. Lock_time — это часть этого общего времени, затраченная на ожидание получения блокировок таблиц или строк. Запрос с Lock_time, близким к Query_time, является проблемой конкуренции блокировок, а не проблемой индекса — исправление предполагает проектирование транзакций или уменьшение области блокировки, а не добавление индексов.
Почему мой файл журнала медленных запросов пуст, хотя slow_query_log = ON?
Наиболее распространённые причины: (1) ни один запрос ещё не превысил long_query_time — проверьте с помощью SHOW GLOBAL STATUS LIKE 'Slow_queries'; (2) путь к файлу журнала не существует или пользователь mysql не имеет прав на запись; (3) на системах с SELinux контекст файла неверен; (4) переменная slow_query_log_file указывает на другой путь, чем файл, который вы проверяете — подтвердите с помощью SHOW VARIABLES LIKE 'slow_query_log_file'.
Как найти единственный наиболее проблемный запрос в журнале медленных запросов?
Запустите pt-query-digest и отсортируйте по R/Call (проверенных строк на вызов) или Response time (общее накопленное время). Запрос в верхней части рейтинга Response time потребляет наибольшее совокупное время базы данных и должен быть первым объектом для анализа EXPLAIN и оптимизации индексов. Если pt-query-digest недоступен, используйте mysqldumpslow -s t -t 1 для извлечения единственного запроса с наибольшим общим временем.
