Когда я впервые услышал словосочетание «база данных», мне представилось что-то огромное и страшное: серверная комната, гул вентиляторов, люди с очень серьёзными лицами. На деле база данных — это аккуратный шкаф с карточками. Я объясняю это новичкам одинаково уже лет десять, и объяснение работает. Попробую и на тебе.
База данных — это картотека, только очень дисциплинированная
Представь старую библиотечную картотеку: деревянный шкаф, в нём ящики, в ящиках карточки. На каждой карточке одна книга — автор, название, год, номер полки. Ящик здесь это таблица. Карточка — строка (её ещё называют записью). Поля на карточке — колонки. Всё, устройство реляционной базы данных ты только что понял.
Отличий от настоящей картотеки два. Первое: у каждой карточки есть уникальный номер — первичный ключ, чтобы её нельзя было спутать ни с какой другой. Второе: ящики умеют ссылаться друг на друга. В ящике «пользователи» лежит карточка Игоря с номером 17, а в ящике «заказы» у каждого заказа написано «владелец: 17». Это внешний ключ, и на нём держится вся магия: база сама соберёт «все заказы Игоря», не заставляя тебя бегать между ящиками.
SQL: как разговаривать с картотекой
SQL — это не база данных, а язык запросов к ней. Читается он почти как английская фраза: SELECT name FROM users WHERE city = 'Казань' — «возьми имя из пользователей, где город Казань». Ты описываешь, что хочешь получить, а не как это искать. Как искать, база придумает сама.
Именно поэтому SQL сорок с лишним лет не уходит из моды. По опросу Stack Overflow 2025 самой используемой базой у разработчиков стал PostgreSQL — 55,6% (годом раньше было 48,7%), за ним MySQL с 40,5% и SQLite с 32%. Все они говорят на SQL. Выучив его один раз, ты сможешь работать почти с любой.
SQL — редкий навык, который не устаревает. Фреймворки меняются каждые два года, а SELECT ... FROM ... WHERE ты напишешь и через десять лет, просто к другой базе.
SQL или NoSQL: когда что брать
NoSQL — зонтичный термин для всего, что устроено не как таблицы. Внутри него минимум четыре семейства: документные базы (MongoDB) хранят объекты вроде JSON, ключ-значение (Redis) — просто «ключ → значение», колоночные (Cassandra) заточены под гигантский поток записи, графовые (Neo4j) — под связи вида «друг друга друга».
Правило, к которому я пришёл на практике, простое. Если данные связаны между собой и ошибка стоит денег — заказы, платежи, склад, — бери SQL. У него есть ACID: перевод либо прошёл целиком, либо не прошёл вовсе, промежуточного состояния не бывает. Если данные разнородные, схема меняется каждую неделю, а запросы простые («дай по ключу») — сессии, кэш, логи, лента событий, — удобнее NoSQL.
И главное: это не выбор «или-или». Проценты в опросах в сумме дают сильно больше ста именно потому, что нормальный проект держит PostgreSQL как основную базу и рядом Redis под кэш. Так делают почти все, и это не компромисс, а норма.

Индекс: почему без него всё тормозит
Вот тут начинается самое полезное. Представь, что тебя попросили найти в картотеке карточку человека с конкретной почтой, а карточки лежат в порядке поступления. Придётся перебирать подряд — все два с половиной миллиона. База поступает ровно так же: это называется полный перебор, в плане запроса он подписан как Seq Scan, и на большой таблице занимает секунды.
Индекс — это отдельный ящичек, где те же карточки продублированы, но уже отсортированы по нужному полю, и на каждой написано, где лежит оригинал. Технически это чаще всего B-дерево: сверху корень, ниже ветки, и каждый шаг отсекает большую часть данных. Вместо двух миллионов сравнений получается пара десятков — и запрос из 2300 миллисекунд превращается в 3.
Бесплатно это не бывает. Индекс занимает место на диске и обновляется при каждой вставке. Знакомая история: на таблице висело двенадцать индексов «на всякий случай», пакетная вставка шла пять минут; оставили четыре нужных — стало тридцать секунд. Индексы ставят на то, по чему реально ищут, соединяют и сортируют, а не на все колонки подряд.

Пять ошибок, на которых спотыкаются все
1. SELECT * везде
Ты тащишь по сети все колонки, включая жирное текстовое поле, которое тебе вообще не нужно. Перечисляй поля явно — это и быстрее, и честнее по отношению к тому, кто будет читать код после тебя.
2. Запрос внутри цикла
Достал сто постов, а потом для каждого отдельным запросом достаёшь автора — сто один поход в базу вместо одного. Это классическая проблема N+1. Лечится соединением таблиц через JOIN или одним запросом с условием IN.
3. Функция поверх колонки в условии
Условие вида WHERE YEAR(created_at) = 2026 заставляет базу вычислить функцию для каждой строки, и индекс на created_at перестаёт работать. Пиши диапазоном: created_at >= '2026-01-01'. Индекс сразу оживает.
4. Выбор базы по моде
«Возьму MongoDB, он модный» — а через полгода выясняется, что данные у тебя сплошь связанные, и ты руками собираешь джойны в коде приложения. Сначала access patterns — как ты будешь читать данные, — и только потом выбор базы.
5. Не смотреть в план запроса
В любой SQL-базе есть команда EXPLAIN: она показывает, что база собирается делать. Одна строчка — и видно, читает она таблицу целиком или идёт по индексу. Это самый дешёвый способ понять, почему тормозит, и его почему-то почти никто не открывает.
Если совсем коротко: база данных — это картотека, SQL — вежливая просьба к ней, индекс — оглавление, без которого приходится листать всё подряд. Дальше только практика: поставь PostgreSQL или хотя бы SQLite (он вообще один файл), налей туда сотню тысяч строк и поиграй с индексами — разницу почувствуешь руками. А у тебя какой запрос тормозил дольше всего и чем в итоге оказалась причина?


Пока нет комментариев