Модуль 14

Indexes and Performance Basics

Ось готовий урок, створений за твоїм майстер-промптом у стилі David Malan.


🎓 CS50: Основи Індексів та Продуктивності (Indexes & Performance)

Привіт, друзі! Ласкаво просимо! 👋

Сьогодні ми не просто пишемо код, який працює. Ми вчимося писати код, який літає. Ми заглянемо під капот баз даних і розберемося з темою, яка відрізняє новачка від інженера, здатного будувати масштабовані системи.

Тема сьогоднішнього уроку: Індекси (Indexes).


1. 🔥 Вступ: Голка в копиці сіна

Уявіть собі ситуацію. Я даю вам товстенний телефонний довідник міста Нью-Йорк (пам'ятаєте такі?). У ньому мільйон імен. Але є одна проблема: імена в ньому записані не за алфавітом, а у випадковому порядку.

Я прошу вас знайти номер телефону "Malan, David".

Питання до вас: Як ви будете це робити?

Ви відкриваєте першу сторінку. Там "Malan"? Ні. Друга? Ні. Третя? Ні. У найгіршому випадку (worst-case scenario), вам доведеться переглянути кожну сторінку до останньої, щоб знайти мене. Якщо в книзі 1 000 сторінок, ви зробите 1 000 перевірок. Це ми називаємо лінійною складністю, або O(n).

А тепер уявіть, що це не телефонна книга, а база даних Facebook або Instagram з мільярдом користувачів. Якщо ви шукаєте профіль друга і база даних переглядає кожен запис по черзі... ви отримаєте результат десь наступного вівторка. 🐢

Навіщо нам ця тема? Тому що ніхто не любить чекати. Якщо ваш сайт вантажиться довше 2 секунд, користувач йде до конкурента. Індекси — це магія, яка перетворює пошук з годин на мілісекунди.


2. 🧠 Теоретична база: Як це працює "під капотом"

Що ж таке Індекс?

Індекс — це спеціальна структура даних (окрема "книжечка"), яка зберігає значення певної колонки у відсортованому вигляді разом із "вказівником" (посиланням) на те місце, де лежить повний рядок даних.

Давайте повернемося до аналогії.

Згадайте підручник. * Тіло книги — це ваша таблиця з даними. Там багато тексту. * Зміст у кінці книги (Subject Index) — це і є наш SQL-індекс.

Якщо ви шукаєте тему "B-Trees", ви не читаєте всю книгу. Ви йдете в кінець, знаходите "B-Trees" (вони там за алфавітом!), бачите цифру "сторінка 42", і миттєво відкриваєте сторінку 42.

Що відбувається технічно?

Коли ви створюєте індекс для колонки (наприклад, email), база даних (PostgreSQL, MySQL тощо) робить наступне: 1. Бере всі email-и. 2. Сортує їх. 3. Будує деревоподібну структуру (зазвичай B-Tree — збалансоване дерево).

Завдяки цьому пошук стає бінарним. Замість перевірки мільйона записів, база даних просто ділить список навпіл: "Мій email більший чи менший за середину?". І так за лічені кроки знаходить потрібне. Це складність O(log n).

⚠️ Що треба зрозуміти інтуїтивно (Trade-offs):

У світі Computer Science нічого не дається безкоштовно. * Плюс: Читання (SELECT) стає блискавичним. 🚀 * Мінус: Запис (INSERT, UPDATE, DELETE) стає повільнішим. 🐌

Чому? Бо коли ви додаєте нового користувача, база даних тепер мусить не просто кинути дані в таблицю, а ще й знайти правильне місце в "алфавітному" індексі й оновити дерево.


3. 🧪 Приклади: Від повільного до миттєвого

Давайте подивимось на це в дії. Уявімо, що у нас є таблиця users з 1 мільйоном рядків.

Сценарій 1: Пошук без індексу

SELECT * FROM users WHERE email = 'david@harvard.edu';

Що ви очікуєте побачити? База даних каже: "Окей, я не знаю, де цей Девід. Я почну з рядка №1 і буду читати до №1 000 000". Технічною мовою це називається Full Table Scan (повне сканування таблиці). Це повільно. Це боляче.

Сценарій 2: Створення індексу

Ми кажемо базі: "Гей, будь ласка, запам'ятай email у відсортованому порядку".

CREATE INDEX idx_users_email ON users(email);

Тепер виконуємо той самий запит:

SELECT * FROM users WHERE email = 'david@harvard.edu';

Результат: База йде в індекс, за 3-4 "стрибки" знаходить 'david@harvard.edu', бере посилання на рядок і повертає дані. Час виконання падає з 500 мс до 1 мс.

Сценарій 3: Складніший приклад

А що, якщо ми шукаємо ось так?

SELECT * FROM users WHERE age > 25 AND city = 'Kyiv';

Якщо індекс є тільки на email, він нам тут не допоможе! База знову піде сканувати всю таблицю. Нам потрібен складений індекс (Composite Index) або окремі індекси на ці поля, але про це — в практичній частині.


4. 🛠 Практична частина

Прийшов час забруднити руки! (Або просто нагріти клавіатуру). Уявімо, що ми працюємо з PostgreSQL або SQLite.

Завдання 1: Setup Створіть таблицю students і наповніть її даними (якщо не можете згенерувати мільйон, зробіть хоча б 1000, або уявіть, що їх там мільйон).

CREATE TABLE students (
    id SERIAL PRIMARY KEY,
    name VARCHAR(100),
    phone VARCHAR(20)
);
-- Уявіть тут INSERT тисяч рядків...

Завдання 2: Вимірювання (Benchmark) Спробуйте знайти студента за номером телефону до створення індексу. Використайте команду EXPLAIN ANALYZE (це рентген для вашого запиту).

EXPLAIN ANALYZE SELECT * FROM students WHERE phone = '555-0199';

Знайдіть у виводі слова "Seq Scan" (Sequential Scan). Запишіть час виконання.

Завдання 3: Оптимізація Створіть індекс на колонку phone.

CREATE INDEX idx_phone ON students(phone);

Завдання 4: Момент істини Запустіть той самий EXPLAIN ANALYZE знову. Що змінилося? Чи бачите ви тепер "Index Scan" або "Bitmap Heap Scan"? Як змінився час?

Завдання 5: Підступне питання (Міні-кейс) Ви створили індекс на name. Ви робите запит:

SELECT * FROM students WHERE name LIKE '%David';

(Ми шукаємо всіх, чиє ім'я закінчується на David). Питання: Чи спрацює тут індекс? Підказка: Якщо ви шукаєте в словнику слова, що закінчуються на "…apple", чи допомагає вам алфавітний порядок? (Ні. Індекс зазвичай працює з початку рядка, тобто David%).

Завдання 6: "А що, якщо..." Що, як ми створимо індекси на кожну колонку в таблиці? Це хороша ідея? Чому ні? (Згадайте про операції INSERT/UPDATE).


5. 💡 Мислення як у розробника

Як думає Senior Developer, коли проектує базу даних?

  1. Не оптимізуй передчасно. Не створюйте індекси "про всяк випадок". Створюйте їх там, де ви знаєте, що будуть часті пошуки (колонки в WHERE, JOIN, ORDER BY).
  2. Аналізуй плани виконання. Команда EXPLAIN — ваш найкращий друг. Не гадайте, чому запит повільний — запитайте у бази.
  3. Унікальність. Якщо колонка повинна бути унікальною (наприклад, username), створення UNIQUE INDEX вбиває двох зайців: і швидкість дає, і дублікати забороняє.

Типова помилка новачка: Створити індекс на колонку з дуже малою різноманітністю даних (low cardinality). Приклад: Колонка gender (значення 'M' або 'F'). Якщо у вас 50% чоловіків і 50% жінок, індекс не допоможе. Базі простіше прочитати все підряд, ніж стрибати туди-сюди по дереву індексу, щоб вибрати половину таблиці. Індекс ефективний, коли він відсіює більшість даних.


6. 🧩 Підсумок

Отже, що ми сьогодні дізналися:

  1. Індекс — це як алфавітний покажчик у книзі. Він прискорює пошук (SELECT), але трохи уповільнює зміни (INSERT/UPDATE).
  2. Full Table Scan — це зло для великих даних. Ми хочемо Index Scan.
  3. Ми навчилися використовувати EXPLAIN, щоб бачити, як база даних "думає".

Тепер ви не просто пишете SQL-запити. Ви пишете запити, які витримають навантаження реального світу. Ви вмієте балансувати між швидкістю читання та запису.

Що далі? Тепер, коли наші запити літають, виникає інше питання: а що, якщо під час запису даних вимкнеться світло? Або два користувачі одночасно куплять останній квиток у кіно? На наступному уроці ми поговоримо про Транзакції та ACID. Це буде вибухово! 🧨

А поки що — це був CS50. Побачимось!