کتابفروشی صد هزار جلد دارد. مشتری میگوید «همه کتابهای همین نویسنده». اگر قفسهها را از اول تا آخر بگردی، ظهر تمام میشود. یک کارتکاتالوگ کنار در میگذاری: نام نویسنده → شماره قفسه. اسم این فهرست Index است.
Index یک ساختار جانبی است — معمولاً B-Tree — که بهجای گشتن کل جدول، میانبر میدهد. جستجو از O(n) میشود O(log n). در جدول ۱۰۰ میلیونی، فرق 10ms با دو دقیقه است. بدون آن، دیتابیس هر بار Full Table Scan میکند: هر قفسه، هر جلد.

کوئری کند، و نجاتش
جدول orders را تصور کن. «سفارشهای کاربر ۸۱۲۳» بدون فهرست یعنی خواندن همه سطرها. یک Index روی user_id همان کارتکاتالوگ است. اگر معمولاً «سفارشهای اخیر همان کاربر» را میخواهی، فهرست مرکب دقیقتر است.
-- کوئری کند: Full Table Scan
SELECT * FROM orders WHERE user_id = 8123;
-- نجات:
CREATE INDEX idx_orders_user ON orders (user_id);
-- کوئری مرکب رایج: سفارشهای اخیر یک کاربر
CREATE INDEX idx_user_created ON orders (user_id, created_at DESC);قواعدی که هزینه را نشان میدهند
Index رایگان نیست. هر کدام یک وام است که با هر نوشتن قسطش را میدهی. جدول write-heavy با ده فهرست = کتابفروشیای که هر کتاب تازه را در ده کاتالوگ جدا هم ثبت میکند.
- Index مرکب (a, b) به کوئری روی a و روی (a,b) کمک میکند، ولی به کوئری فقط روی b نه — ترتیب ستونها مهم است: قانون چپترین پیشوند.
- هر Index نوشتن را کند میکند: INSERT و UPDATE باید همه درختها را هم بهروز کنند.
- Covering Index: اگر همه ستونهای موردنیاز کوئری داخل Index باشد، اصلاً به جدول — همان قفسه — مراجعه نمیشود.
- اول با EXPLAIN ببین دیتابیس واقعاً چه میکند؛ حدس نزن. Query Plan شغلش نشان دادن همین مسیر است.
سه جور فهرست، سه شغل
همه Index ها یک شکل نیستند. شغل را بفهم، بعد ساختار را انتخاب کن.
به زبان ساده
Index کارتکاتالوگ کتابفروشی است: بهجای گشتن همه قفسهها، مستقیم سراغ محل جواب میروی.
مثال واقعی
برای سفارشهای یک کاربر در جدول صد میلیونی، Index روی user_id از Full Table Scan جلوگیری میکند.