اگه دیتابیس شما کند شده، احتمالاً مشکل ایندکس نداشتنه. ایندکس‌گذاری درست میتونه سرعت کوئری رو ۱۰۰ برابر بالا ببره. تو این مقاله راهنمای کامل رو یاد میگیرید.

Index چیه؟

مثل فهرست کتاب هست. به جای گشتن کل جدول، دیتابیس به فهرست نگاه میکنه و سریع پیدا میکنه. بدون ایندکس، MySQL باید همه سطرها رو بخونه (Full Table Scan).

انواع Index

B-Tree: پیش‌فرض، برای WHERE، ORDER BY.
Hash: فقط برای Equality، خیلی سریع.
Full-text: برای جستجو در متن.
Spatial: برای Geographic data.
Composite: چند ستون با هم.

ساخت Index

CREATE INDEX idx_email ON users(email);

یا در CREATE TABLE:
CREATE TABLE users (id INT, email VARCHAR(255), INDEX (email));

Composite Index

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

ترتیب مهمه! ستونی که بیشتر فیلتر میکنه اول.

Unique Index

مثل Primary Key، مقدار تکراری قبول نمیکنه:
CREATE UNIQUE INDEX idx_email ON users(email);

کی Index بذارم؟

ستون‌های WHERE: ستونی که تو WHERE استفاده میشه.
ستون‌های JOIN: Foreign Key.
ستون‌های ORDER BY: برای مرتب‌سازی سریع.
ستون‌های GROUP BY: تجمیع سریع‌تر.

کی Index نذارم؟

ستون‌های با تغییر زیاد: Index رو مدام باید آپدیت کنه.
ستون‌های کم Cardinality: مثل جنسیت (فقط 2 مقدار). Index مفید نیست.
جداول کوچک: Full Scan سریع‌تر.
ستون‌هایی که استفاده نمیشن.

EXPLAIN

قبل از هر کوئری EXPLAIN بزنید:
EXPLAIN SELECT * FROM users WHERE email = test;

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

Covering Index

Index شامل همه ستون‌های SELECT. دیتابیس فقط از Index میخونه، جدول اصلی رو نه.

SELECT id, name FROM users WHERE email = test;
INDEX(email, id, name) → Covering

Prefix Index

برای ستون‌های طولانی:
CREATE INDEX idx_content ON articles(content(100));

فقط ۱۰۰ کاراکتر اول رو Index میکنه. فضا کمتر.

Descending Index

در MySQL 8+:
CREATE INDEX idx_created ON posts(created_at DESC);

Full-text Index

برای جستجوی متنی:
CREATE FULLTEXT INDEX idx_content ON articles(title, content);
SELECT * FROM articles WHERE MATCH(title, content) AGAINST(keyword);

Multiple Column Index Rules

Left-most Prefix: INDEX(a, b, c) کار میکنه برای:
- WHERE a
- WHERE a AND b
- WHERE a AND b AND c
ولی نه برای WHERE b یا WHERE c.

Index Cardinality

تعداد مقادیر منحصر به فرد. بالاتر بهتر.
SHOW INDEX FROM users;

مشکلات رایج

Too Many Indexes

هر Index حافظه میگیره و INSERT رو کند میکنه. فقط لازم رو بذارید.

Wrong Order

INDEX(city, country) برای WHERE country خوب نیست. ترتیب مهمه.

Function در WHERE

WHERE YEAR(created_at) = 2026 از Index استفاده نمیکنه.
WHERE created_at BETWEEN '2026-01-01' AND '2026-12-31' استفاده میکنه.

LIKE با % ابتدا

WHERE name LIKE '%mohammad%' → Full Scan.
WHERE name LIKE 'mohammad%' → Index استفاده میشه.

Composite Index بهینه

WHERE status = 1 AND created_at > NOW() - INTERVAL 1 DAY:
INDEX(status, created_at)

Analyze Table

Statistics رو به‌روز کنید:
ANALYZE TABLE users;

Redundant Index

اگه INDEX(a, b) دارید، نیازی به INDEX(a) نیست. حذف کنید.

Unused Index

Index هایی که استفاده نمیشن رو پیدا و حذف کنید:
SELECT * FROM sys.schema_unused_indexes;

Index Size

بررسی حجم Index:
SELECT * FROM sys.schema_index_statistics;

Postgres Indexing

PostgreSQL انواع بیشتری داره: B-tree، Hash، GiST، GIN، BRIN. برای موقعیت‌های خاص انتخاب کنید.

Practical Example

جدول orders با 10 میلیون سطر.
کوئری: SELECT * FROM orders WHERE customer_id = 100 ORDER BY created_at DESC LIMIT 10;
بدون Index: 30 ثانیه
با INDEX(customer_id, created_at): 0.05 ثانیه

Monitoring

Slow Query Log و pt-query-digest برای پیدا کردن کوئری‌های که نیاز به Index دارن.

سباهاست پیشنهاد

در سرور های سباهاست، MySQL با تنظیمات بهینه و ابزارهای مانیتورینگ آماده‌ست.

جمع‌بندی

Index هوشمند تفاوت بین سایت کند و سریع رو میسازه. با EXPLAIN، Slow Query Log و اصولی که یاد گرفتید، دیتابیستون رو حرفه‌ای بهینه کنید.