Модуль 9

Первинні ключі та індекси

Ось твій урок у стилі David Malan (CS50). Приготуйся, зараз буде цікаво!


🎓 CS50: Первинні ключі та індекси (Primary Keys & Indexes)

Привіт, друзі! 👋 Радий вас бачити.

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

Уявіть, що ви зайшли до гігантської бібліотеки. У ній — мільйон книг. Але є одна маленька проблема: книги на полицях розставлені абсолютно хаотично. "Гаррі Поттер" лежить десь між підручником з квантової фізики та кулінарною книгою 19-го століття.

Я прошу вас знайти книгу «Кобзар». Питання до вас: Скільки часу це займе?

Годину? День? Тиждень? Вам доведеться брати кожну книгу в руки, дивитися на обкладинку і відкладати, якщо це не те. Це називається Linear Search (лінійний пошук). Якщо у вас мільйон записів, у найгіршому випадку вам доведеться перевірити мільйон книг.

А тепер уявіть, що ви підходите до бібліотекаря, і він дає вам каталог, де написано: "Кобзар, Тарас Шевченко — Ряд 4, Шафа 2, Полиця 5".

Ви йдете прямо туди і берете книгу за 30 секунд. Ось це і є сила Індексів.

Але як бібліотекар знає, що ця книга унікальна? Що, якщо є дві різні книги з однаковою назвою? Тут на сцену виходить Первинний ключ (Primary Key).

Без цих двох понять будь-яка база даних (Facebook, Instagram, "Дія") перетворилася б на найповільнішу річ у світі вже після першої тисячі користувачів. Сьогодні ми розберемося, як не дати вашій системі "померти". Поїхали! 🚀


2. 🧠 Теоретична база: Що "під капотом"?

Давайте спростимо все до неможливості.

🔑 Первинний ключ (Primary Key / PK)

Це — унікальний ідентифікатор кожного рядка у вашій таблиці.

  • Аналогія: Ваш ідентифікаційний код (ІПН) або номер паспорта. Людей з іменем "Олександр Бондаренко" може бути тисячі. Але "Олександр Бондаренко" з кодом 1234567890 — лише один.
  • Правило №1: Він ніколи не повторюється.
  • Правило №2: Він не може бути пустим (NULL).
  • Як це працює: База даних автоматично створює "паркан", який не дозволить вам додати дублікат.

📑 Індекс (Index)

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

  • Аналогія: Алфавітний покажчик у кінці підручника. Ви хочете знайти термін "Поліморфізм". Ви не гортаєте весь підручник. Ви йдете в кінець, знаходите літеру "П", бачите сторінку 42 і відкриваєте її.
  • Як це працює: Замість того, щоб перебирати 1,000,000 записів (що довго), база даних використовує алгоритм бінарного пошуку (як у грі "Вгадай число": більше/менше). Це дозволяє знайти потрібне за лічені кроки.

❗️ Запам'ятайте: Індекси прискорюють читання (SELECT), але уповільнюють запис (INSERT/UPDATE). Чому? Бо коли ви додаєте нову книгу в бібліотеку, вам тепер треба не просто кинути її на стіл, а ще й внести запис у картковий каталог (індекс).


3. 🧪 Приклади: Від хаосу до порядку

Давайте подивимось на це в коді (SQL).

Сценарій 1: Хаос (Без ключів)

Уявіть таблицю користувачів.

CREATE TABLE users (
    name VARCHAR(50),
    email VARCHAR(50)
);

Ми додаємо Ілона Маска:

INSERT INTO users (name, email) VALUES ('Elon', 'elon@tesla.com');
INSERT INTO users (name, email) VALUES ('Elon', 'elon@tesla.com'); -- Ой!

Що ви очікуєте? Помилку? Реальність: База мовчки створить двох Ілонів. Тепер у вас дублікати. Як їх розрізнити? Ніяк. Це катастрофа для логіки програми.

Сценарій 2: Порядок (Primary Key)

Виправляємо ситуацію. Додаємо id як первинний ключ.

CREATE TABLE users (
    id SERIAL PRIMARY KEY, -- SERIAL означає автоінкремент (1, 2, 3...)
    name VARCHAR(50),
    email VARCHAR(50)
);

Тепер, навіть якщо імена однакові, id будуть різні (1 і 2). А якщо ми спробуємо вставити запис з існуючим id — база даних "накричить" на нас червоною помилкою. Це цілісність даних.

Сценарій 3: Швидкість (Index)

У нас є 1,000,000 користувачів. Ми шукаємо когось за email:

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

Без індексу база перевіряє кожен рядок. Це займає, скажімо, 2 секунди. Для вебу це вічність!

Створимо індекс:

CREATE INDEX idx_users_email ON users(email);

Тепер той самий запит займає 0.005 секунди. Чому? База пішла в "алфавітний покажчик", миттєво знайшла адресу і дістала дані. Магія? Ні, Computer Science!


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

Час забруднити руки кодом! Виконайте наступні завдання (у голові або в SQL-редакторі):

  1. 🔹 Створити таблицю «Products» Вона має містити id (PK), name (назва товару), sku (артикул) і price.

  2. 🔹 Експеримент з дублікатами Спробуйте вставити два товари з однаковим id. Що сказала база даних? Запишіть цю помилку, ви будете бачити її часто.

  3. 🔹 Унікальність без ID id — це добре, але чи можуть у нас бути два товари з однаковим артикулом (sku)? Мабуть, ні. Додайте обмеження UNIQUE для колонки sku. Це теж створює індекс під капотом!

  4. 🔹 Пошукова задача (Міні-кейс) Уявіть, що ви розробляєте Uber. У вас є таблиця поїздок trips (мільйони рядків). Водій часто запитує історію своїх поїздок: SELECT * FROM trips WHERE driver_id = 555. Питання: На яку колонку треба повісити індекс, щоб додаток у водія не гальмував?

  5. 🔹 "А що, якщо..." Що буде, якщо ми створимо індекс на колонку gender (стать), де є лише два варіанти ("M" і "F")? Чи допоможе це прискорити пошук? (Підказка: Якщо бібліотекар скаже вам "Книга в тій половині бібліотеки, де всі сині книги", а синіх книг — 50%, це не дуже допоможе. Це називається низька селективність).


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

Як відрізнити новачка від профі в цій темі?

❌ Типова помилка новачка:

"Індекси прискорюють все! Я створю індекси для кожної колонки!" Результат: Ваша база даних "літає" на читання, але коли користувач намагається зареєструватися (INSERT), це займає вічність, бо базі треба оновити 10 індексів одночасно.

🧠 Як думає Senior Developer:

  1. PK обов'язковий завжди. (Найчастіше це просто id).
  2. Аналізуємо запити. Я не створюю індекси наосліп. Я дивлюся, які WHERE запити найчастіші. Якщо ми часто шукаємо за email — індексуємо email. Якщо ніколи не шукаємо за date_of_birth — не чіпаємо його.
  3. Баланс. Індекс — це компроміс між швидкістю читання та швидкістю запису (і місцем на диску).

💡 Порада з практики:

Завжди використовуйте команду EXPLAIN перед вашим запитом (наприклад, EXPLAIN SELECT...). База даних чесно покаже вам, чи використовує вона індекс (Index Scan), чи тупо перебирає все підряд (Seq Scan). Це ваш рентген!


6. 🧩 Підсумок

Отже, що ми сьогодні вивчили?

  1. Первинний ключ (PK) — це паспорт рядка. Гарантує унікальність і дає швидкий доступ за ID.
  2. Індекс — це прискорення пошуку. Як алфавітний покажчик у книзі.
  3. Ціна швидкості — індекси займають місце і трохи уповільнюють запис нових даних.

Тепер ви вмієте: Не просто створювати таблиці, а проектувати їх так, щоб вони не падали під навантаженням. Ви знаєте різницю між просто "зберіганням" даних і "ефективним доступом" до них.

🔜 У наступній серії: У нас є таблиця Users і таблиця Orders. Як сказати базі, що "Ось це замовлення належить саме цьому користувачу"? Ми поговоримо про Зовнішні ключі (Foreign Keys) і магію зв'язків JOIN.

Це був CS50. Побачимось! 👋