وقتی سایت کند میشه، اغلب مشکل MySQL هست. Slow Query Log ابزار قدرتمندی برای پیدا کردن کوئری‌های مشکل‌داره. تو این مقاله کامل استفاده رو یاد میگیرید.

Slow Query Log چیه؟

ویژگی MySQL که هر کوئری بیشتر از یه زمان مشخص طول میکشه رو ثبت میکنه. با تحلیلش، مشکلات performance رو پیدا میکنید.

فعال‌سازی

در my.cnf

[mysqld]
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 1
log_queries_not_using_indexes = 1

Runtime

SET GLOBAL slow_query_log = 'ON';
SET GLOBAL long_query_time = 1;

پارامترها

long_query_time

حداقل زمان کوئری برای log. مثلاً 1 = یک ثانیه.

log_queries_not_using_indexes

کوئری‌های بدون Index رو هم log کنید، حتی اگه سریع باشن.

min_examined_row_limit

حداقل تعداد سطر بررسی شده.

ساختار Log

هر کوئری در Log:

# Time: 2026-07-23T10:30:15
# User@Host: root[root] @ localhost []
# Query_time: 2.5 Lock_time: 0.1
# Rows_sent: 100 Rows_examined: 100000
SELECT * FROM orders WHERE customer_id = 42;

ابزار تحلیل

mysqldumpslow

ابزار پیش‌فرض:

mysqldumpslow -s t -t 10 /var/log/mysql/slow.log

ده کوئری کند رو نشون میده.

pt-query-digest

حرفه‌ای‌ترین:

pt-query-digest slow.log > report.txt

گزارش کامل، خلاصه.

Percona QAN

GUI برای تحلیل.

مثال تحلیل

پرترافیک‌ترین

کوئری‌های که زیاد اجرا میشن. Cache کنید.

کندترین

کوئری‌هایی که بیشترین زمان میگیرن.

بیشترین ردیف

کوئری‌هایی که هزاران ردیف بررسی میکنن.

EXPLAIN

بعد پیدا کردن کوئری کند:

EXPLAIN SELECT * FROM orders WHERE customer_id = 42;

ستون‌ها:

- type: ALL = بد، ref = خوب، const = عالی
- possible_keys: Indexهای موجود
- key: Index استفاده شده
- rows: تخمین سطر بررسی

راه‌حل‌های رایج

Index

ALTER TABLE orders ADD INDEX idx_customer_id (customer_id);

Composite Index

برای WHERE با چند شرط:
CREATE INDEX idx_customer_status ON orders(customer_id, status);

Cover Index

Index شامل همه ستون‌های SELECT.

Limit

SELECT ... LIMIT 100;

Not SELECT *

فقط ستون‌های لازم:
SELECT id, name FROM users;

Cache Layer

Redis یا Memcached برای کوئری‌های تکراری.

N+1 Problem

مثال Bad:
// در حلقه
SELECT * FROM users;
foreach ($users as $user) {
SELECT * FROM orders WHERE user_id = $user->id;
}

راه‌حل: JOIN یا Eager Loading.

Full Table Scan

type = ALL در EXPLAIN. یعنی همه جدول رو میخونه.

راه: Index مناسب.

File Sort

Extra = Using filesort. برای ORDER BY بدون Index.

راه: Index روی ORDER BY column.

Temporary Table

Extra = Using temporary. MySQL جدول موقت میسازه.

راه: پیچیدگی کوئری رو کم کنید.

LIKE % در ابتدا

Bad: WHERE name LIKE '%محمد%';

Good: WHERE name LIKE 'محمد%';

یا Full-text Search.

OR در WHERE

OR گاهی Index رو نادیده میگیره.

راه: UNION یا refactor.

Function در WHERE

Bad: WHERE YEAR(created_at) = 2026
Good: WHERE created_at >= '2026-01-01' AND created_at < '2027-01-01'

Partitioning

برای جداول خیلی بزرگ، Partition بر اساس تاریخ یا ID.

Denormalization

گاهی Duplicate کردن داده برای سرعت.

Read Replica

Read کوئری‌ها به سرور دوم.

Monitoring

Percona Monitoring

Dashboard رایگان.

New Relic

پولی، عمیق.

Simple: cron

هر شب mysqldumpslow اجرا و ایمیل کنید.

Log Rotation

Slow Log بزرگ میشه. Logrotate تنظیم کنید:

/var/log/mysql/slow.log {
daily
rotate 7
compress
}

Production تنظیمات

long_query_time = 2 (کمتر لاگ)
log_queries_not_using_indexes = 0 (فقط مشکلات جدی)

WordPress نمونه

کوئری‌های autoload option معمولاً مشکل‌دارن. delete_option برای پاک کردن.

Laravel نمونه

N+1 معمولاً. with() برای Eager Loading.

Test در Staging

قبل تغییر production، در Staging تست کنید.

جمع‌بندی

Slow Query Log کلید بهینه‌سازی MySQL هست. با تحلیل منظم، مشکلات performance رو پیدا و رفع میکنید.

سباهاست Slow Query Log رو خودکار فعال میکنه.