אינדקסים במסדי נתונים (SQL Indexes)

אינדקסים (Indexes) במסדי נתונים רלציוניים (SQL) הם כמו תוכן עניינים בספר: במקום שהמסד יסרוק שורה שורה את כל הטבלה (Full Table Scan) כדי למצוא מידע, האינדקס מאפשר לו למצוא את השורה במינימום זמן.
ממש כמו בספר, שבמקום לקרוא את כולו, אנחנו ניגש לתוכן העניינים על מנת למצוא נושא מסוים.

⚠️ שימו לב!

כל אינדקס שנוסיף לטבלה מאיץ קריאות (SELECT), אבל מאט פעולות כתיבה (INSERT, UPDATE, DELETE) כי המסד חייב לעדכן את האינדקסים בכל שינוי. ולכן יש לנהוג במשנה זהירות בהוספת אינדקסים.

התאמה לשאילתות: אל תייצרו אינדקסים סתם. תסתכלו על ה-EXPLAIN (ראו הרחבה על EXPLAIN כאן) ותראו איפה המסד עושה Full Table Scan, שם נפעיל את סוג האינדקס החכם שמתאים לנו.

Hash Index

אינדקס המבוסס על טבלת גיבוב (Hash Table).

איך זה עובד? מפעיל פונקציית Hash על הערך כדי להגיע ישירות לכתובת הפיזית שלו בזיכרון/דיסק.

שימוש נפוץ: אך ורק לחיפושי שוויון מדויקים (WHERE status = 'ACTIVE').

CREATE INDEX idx_hash_auth_token ON sessions USING HASH (auth_token);

Bitmap Index

אינדקס שבו הערכים מיוצגים כמערך של ביטים (0 או 1) עבור כל שורה בטבלה. נניח שיש לנו טבלת orders (הזמנות) עם 4 שורות בלבד, ויש בה עמודה בשם status שיכולה לקבל שלושה ערכים בלבד: PENDING, SHIPPED, DELIVERED. זוהי קרדינליות נמוכה (Low Cardinality).

איך זה עובד? עמודות שיש להן מעט ערכים ייחודיים (למשל: מין - זכר/נקבה, סטטוס הזמנה - ממתין/ששולם/בוטל).

שימוש נפוץ: מעולה לעמודות עם קרדינליות נמוכה (Low Cardinality) . במערכות Data Warehouse ו-OLAP (ניתוח נתונים כבד) שבהן עושים שאילתות מורכבות עם הרבה תנאים (AND / OR) על עמודות עם מעט ערכים.

CREATE BITMAP INDEX idx_bitmap_order_status ON orders(status);

B-Tree Index

מבנה נתונים בצורת עץ מאוזן (Balanced Tree). זהו האינדקס הנפוץ והברירת מחדל ברוב מסדי הנתונים. זה האינדקס שבו רובנו משתמשים ביום יום.

איך זה עובד? הנתונים מסודרים בסדר ממויין (עולה או יורד). אפשר לחפש בו בסיבוכיות של חיפוש בינארי מהיר (O(log n).

שימוש נפוץ:

CREATE INDEX idx_employees_salary ON employees(salary);

ל-B-Tree Index יש כמה הרחבות, או הגדרה יותר חכמה של B-Tree Index, להלן ההרחבות:

1. Partial Index

אינדקס שמוחל רק על חלק מהשורות בטבלה, בהתאם לתנאי WHERE מוגדר.

איך זה עובד? יש לנו טבלת משתמשים עם מיליון שורות, אבל רק ל-1% מהם יש סטטוס is_active = true ואנחנו מחפשים אותם תמיד. במקום לאנדקס מיליון שורות, נבנה אינדקס חלקי רק על הפעילים.

שימוש נפוץ: כשמעוניינים לאנדקס רק תת-קבוצה של הנתונים.

CREATE INDEX idx_active_users ON users(email) WHERE is_active = true;

2. Filtered Index

ידוע גם בשם Partial Index. יצירת אינדקס עם תנאי סינון מובנה (WHERE). ביצועים מהירים יותר בכתיבה (INSERT, UPDATE, DELETE): כשיש פחות שורות באינדקס, למסד הנתונים לוקח הרבה פחות זמן לעדכן את האינדקס בזמן שינוי נתונים.

איך זה עובד? במערכות רבות יש מיליוני שורות היסטוריות, אבל 99% מהשאילתות מחפשות רק את הנתונים הפעילים כרגע (למשל: משתמשים פעילים, הזמנות שלא נסגרו, תשלומים ממתינים).

שימוש נפוץ: אם ידוע לנו שיש לנו הרבה רשומות שאנחנו "לא צריכים" ביום יום כמו שורות שאינן פעילות. או הרבה ערכי NULL בעמודה ואנחנו צריכים רק את המלאים.

שימו לב: לא ניתן לחפש סטטוס שונה מאינדקס שקבענו במהירות, אם נבחר להשתמש באינדקס זה.

CREATE INDEX idx_pending_orders
ON orders (customer_id, order_date)
WHERE status = 'PENDING';

3. Function-Based Index (או Expression-Based Index)

אינדקס שלא שומר את הערך הגולמי של העמודה, אלא את התוצאה של פונקציה שמופעלת עליה.

איך זה עובד? כשהשאילתות שלך מפעילות פונקציה על עמודה, מה שבד"כ מבטל את השימוש באינדקס רגיל.

שימוש נפוץ: אם מחפשים לפי אותיות קטנות/גדולות לדוגמה: WHERE LOWER(email) = 'test@gmail.com'. אינדקס רגיל על email לא יעזור כאן.

CREATE INDEX idx_lower_email ON users (LOWER(email));

4. Descending Index

אינדקס ממויין מהגדול לקטן (DESC), בניגוד לברירת המחדל שהיא עולה (ASC).

איך זה עובד? כששאילתות רבות מבקשות מיון בסדר הפוך (ORDER BY date DESC), במיוחד בשילוב עם הגבלת תוצאות (LIMIT 10). במסדי נתונים מודרניים, תומך לחלוטין בכיוונים שונים לכל עמודה באינדקס, מה שמונע מהמסד לבצע מיון פיזי נוסף בזמן השליפה.

שימוש נפוץ: חיפוש שאילתות ספציפיות שרוצות להשתמש בסידור מהגדול לקטן, מתאים לנתונים מאוד ספציפיים.

CREATE INDEX idx_logs_created_desc ON system_logs (created_at DESC);
🏠 Back to Orly's Code Corner