Базы данных (Data Base)
8.05K subscribers
669 photos
479 videos
19 files
688 links
Базы данных (Data Base). По всем вопросам @evgenycarter
Download Telegram
SQL vs NoSQL: что выбрать для реального проекта?

Один из самых частых вопросов:
«Нам вообще SQL нужен? Может, сразу MongoDB?»

Разберёмся коротко и по делу 👇


🔷 SQL (PostgreSQL, MySQL, etc.)

Плюсы:
– Строгая схема → меньше ошибок на проде
– Сложные запросы (JOIN, агрегаты) — легко
– ACID-гарантии → важно для денег, заказов, логистики
– Большое комьюнити, mature-тулинги, репликация, индексы

Когда выбирать:
✅ Чёткая структура данных
✅ Много взаимосвязей (нормализация)
✅ Сложные аналитические выборки
✅ Транзакции критичны


🔶 NoSQL (MongoDB, Redis, DynamoDB, etc.)

Плюсы:
– Гибкая схема (можно быстро пихать JSON как есть)
– Горизонтальное масштабирование — встроено
– Подходит для high-load, real-time, event-based систем

Когда выбирать:
✅ Частые изменения структуры данных
✅ Скорость важнее связности
✅ Огромные объёмы с минимальными связями
✅ Event storage, логирование, IoT, временные данные


❗️Частые ошибки:
– "Берём Mongo, потому что модно" — а потом страдаем с джоинами руками
– "Только SQL, потому что так всегда делали" — и не справляемся с масштабом


🔧Часто лучший вариант — гибрид.
Например:
– PostgreSQL → для core бизнес-логики
– Redis → для кеша
– MongoDB → для логов или гибких анкет


Вывод:
Никто не лучше сам по себе. Всё зависит от данных и задач.
А ты чем пользуешься чаще — SQL или NoSQL?

Поделись с командой, если на старте нового проекта 🧠

📲 Мы в MAX

#db

👉 @database_info
👍3
❌ Антипаттерн: UUID как PK без учёта последствий

Выглядит красиво: глобально уникальный идентификатор, можно генерировать на клиенте, удобно в распределённых системах. Но...

💣 Проблемы:
– Большой размер (16 байт vs 4 байта у INT)
– Плохая локальность: индекс B-Tree фрагментируется
– Медленнее вставки, особенно при высоких нагрузках
– Нагружает сеть, если часто передаёшь PK

📉 В PostgreSQL это особенно заметно: индекс на UUID-ключе может вести себя гораздо хуже, чем на BIGSERIAL.


✅ Как делать правильно:

1. Если всё в одной БД: используй BIGINT или BIGSERIAL
2. Если нужен UUID:
– генерируй UUID v7 (появился в 2022, содержит компонент времени → лучше упорядочен)
– либо UUID v1 (временной, но с оговорками по безопасности)
– или комбинируй автоинкремент + случайный суффикс
3. Храни UUID как UUID, а не как VARCHAR(36) — это экономит место и CPU


🧠 UUID — мощный инструмент, но не серебряная пуля. Прежде чем делать его PRIMARY KEY, подумай: что ты реально выигрываешь?

Сохрани, чтобы не собирать фрагментированные индексы вручную 😅

📲 Мы в MAX

#db

👉 @database_info
👍3
Почему одна и та же БД летает на staging и тормозит в проде

Знакомо? На staging сервере — отклик 100мс, на проде — секундные таймауты. Хотя база одна и та же, схема такая же. Что не так?

Вот 5 частых причин:


1. Разный объём данных
На staging — 10k строк, на проде — 10 млн. Индексы, которые "и так нормально", внезапно перестают справляться.

2. Отсутствие/различие индексов
DevOps мог не раскатить нужные индексы в прод. Или, наоборот, staging набит экспериментальными индексами.

3. Параметры конфигурации БД
work_mem, shared_buffers, max_connections — часто в staging минимальны, но в проде тоже забывают подкрутить.

4. Статистика устарела
На проде реже делается ANALYZE, планировщик начинает строить неэффективные планы. Итог — ползёт.

5. Разное поведение приложения
Прод нагружается параллельно десятками потоков. Staging — ты и Postman.


🛠 Что делать:
– Сравни настройки сервера (SHOW ALL;)
– Проверь EXPLAIN ANALYZE
– Не доверяй staging — тестируй на продоподобных данных

📲 Мы в MAX

#db

👉 @database_info
👍3
🚀 Подборка полезных IT каналов в Max


Системное администрирование, DevOps 📌

https://max.ru/i_odmin Все для системного администратора
https://max.ru/bash_srv Bash Советы
https://max.ru/sysadminof Книги для админов, полезные материалы
https://max.ru/i_odmin_book Библиотека Системного Администратора
https://max.ru/i_devops DevOps: Пишем о Docker, Kubernetes и др.
https://max.ru/tipsysdmin Типичный Сисадмин

Excel лайфхак 📌
https://t.me/Excel_lifehack Excel лайфхак

Английский с нуля 🇬🇧
https://max.ru/UchuEnglish

1C разработка 📌
https://max.ru/odin1c_rus Cтатьи, курсы, советы, шаблоны кода 1С

Программирование C++📌
https://max.ru/cpp_lib Библиотека C/C++ разработчика

Программирование Go📌
https://max.ru/golang_lib Библиотека Go (Golang) разработчика

Программирование React📌
https://max.ru/react_lib React

Программирование Python 📌
https://max.ru/python_of Python академия.
https://max.ru/BookPython Библиотека Python разработчика

Java разработка 📌
https://max.ru/bookjava Библиотека Java разработчика

GitHub Сообщество 📌
https://max.ru/githublib Интересное из GitHub

Базы данных (Data Base) 📌
https://max.ru/database_info Все про базы данных

Фронтенд разработка 📌
https://max.ru/frontend_1 Подборки для frontend разработчиков

Библиотеки 📌
https://max.ru/programmist_of Книги по программированию
https://max.ru/proglb Библиотека программиста
https://max.ru/bfbook Книги для программистов

Программирование 📌
https://max.ru/bookflow Лекции, видеоуроки, доклады с IT конференций
https://max.ru/itmozg Программисты, дизайнеры, новости из мира IT
https://max.ru/php_lib Библиотека PHP программиста 👨🏼‍💻👩‍💻

Шутки программистов 📌
https://max.ru/itumor Шутки программистов

Защита, взлом, безопасность 📌
https://max.ru/thehaking Канал о кибербезопасности
https://max.ru/xakkep_1 Хакер Free

Книги, статьи для дизайнеров 📌
https://max.ru/odesigners Статьи, книги для дизайнеров

Математика 📌
https://max.ru/Pomatematike Канал по математике
https://max.ru/phismat_1 Обучающие видео, книги по Физике и Математике

Вакансии 📌
https://max.ru/progjob Вакансии в IT

Мир технологий 📌
https://max.ru/mir_teh Канал для любознательных

Бонус 📌
https://max.ru/piterspb_78 Свежие новости Санкт-Петербурга
https://max.ru/mockva_life Свежие новости Москвы
https://max.ru/piterspb Питер Новости: Санкт-Петербург / СПБ / ДТП
Антипаттерн: использование SELECT * в продакшене

Кажется безобидным, правда? Особенно на этапе прототипирования. Но как только ваш запрос с SELECT * уходит в прод, начинаются проблемы:

🔻 Почему это плохо:

– Избыточные данные. Вы тянете всё, включая ненужные поля. Это бьёт по сети, памяти и CPU.
– Ломкость кода. Добавили колонку в таблицу — и, внезапно, старый код падает, потому что ожидал другую структуру.
– Плохая читаемость. Непонятно, какие поля реально нужны. Это мешает отладке и сопровождению.
– Невозможно использовать covering index — индекс по нужным колонкам не спасёт, если вы вытаскиваете всё подряд.

📌 Как правильно:

✅ Явно указывайте нужные поля:


SELECT id, name, created_at FROM users;


✅ Работаете с ORM — настраивайте выборку полей в select() или .only() (в зависимости от фреймворка).

✅ В аналитике? Даже при джойнах и CTE — указывайте, что реально используете.

🧠 Запомни: чем меньше данных ты запрашиваешь — тем быстрее и стабильнее работает твой код.

💬 А ты встречал SELECT * в проде? Или, может, сам когда-то писал так?

📲 Мы в MAX

#db

👉 @database_info
👍4👎1
🔴 Антипаттерн: игнорирование поведения NULL в SQL

Когда ты пишешь WHERE column != 'value', ты можешь думать, что фильтруешь всё, что не равно 'value'. Но если в колонке есть NULL, такие строки выпадут из выборки. Почему? Потому что NULL != 'value' даёт… UNKNOWN, а не TRUE.

❌ Пример проблемы:


SELECT * FROM users
WHERE status != 'active';


Если status у кого-то NULL — он не попадёт в результат. Неочевидно, но критично.

✔️ Как избежать:

1. Явно учитывай NULL'ы:


SELECT * FROM users
WHERE status != 'active' OR status IS NULL;


2. Работай с COALESCE, если допустимо:


SELECT * FROM users
WHERE COALESCE(status, '') != 'active';


📌 То же касается и =: NULL = 'value' → UNKNOWN
📌 Агрегации (COUNT, AVG`) тоже игнорируют `NULL — помни об этом при аналитике

Вывод:
NULL — не "ничего", а "неизвестно", и SQL строго это уважает. Не учитывая это, легко получить баг, который даже не заметишь сразу.

💡 Всегда проверяй поведение WHERE, JOIN и агрегатов с NULL. Пиши явный код, особенно в проде.

Сохрани, чтобы не ловить баги на ровном месте.

📲 Мы в MAX

#db

👉 @database_info
👍3🔥1
3 способа «убить» индекс в SQL

Запрос тормозит. Индекс есть. Что пошло не так?

Вот 3 способа, которыми ты уже мог его сломать:

▪︎ обернул колонку в функцию
▪︎ поставил wildcard % в начале LIKE
▪︎ допустил неявное преобразование типов

База данных не может нормально использовать индекс по колонке, если сначала ей нужно эту колонку преобразовать.

Главное правило: оставляй колонку “голой” в WHERE.

📲 Мы в MAX

#db

👉 @database_info
👍3🔥2
Что мощнее — S3 или локальные диски?
Разбираем сценарии использования S3-хранилища в связке с Postgres Pro

На вебинаре узнаете о лучших практиках эксплуатации в продакшн-средах. Эксперты Selectel и Postgres Pro разберут все: от резервного копирования через pg_probackup и S3 Selectel до хранения паркетных данных с Postgres Pro AXE и результатов TPC-тестов. Особенно интересно будет архитекторам, техлидам и всем, кто отвечает за надежность и экономику хранения данных.

📍 Онлайн
⏰ 14 июля в 12:00


Регистрируйтесь ➡️ https://slc.tl/hh3pe

Больше мероприятий для ИТ-специалистов в канале @selectel_events. Подписывайтесь!

Реклама. АО "Селектел". erid:2W5zFJxhbub
❤2
🧱 Антипаттерн: использование UUID как Primary Key без оглядки

На первый взгляд, UUID — классный способ генерировать уникальные идентификаторы:
– не зависят от последовательности
– удобны для распределённых систем
– безопасны для внешнего экспонирования

Но если ты просто заменишь SERIAL или BIGINT на UUID в качестве PK — жди сюрпризов:

❌ В чём подвох:
– Производительность INSERT'ов резко падает: UUID случайные → нет locality → индекс (обычно B-Tree) постоянно фрагментируется
– Индексы пухнут: UUID = 16 байт, BIGINT = 8 байт. Разница кажется небольшой, но на больших объёмах — это боль
– Чтение медленнее: за счёт увеличенного размера индексов и меньшего кэш-хита

✅ Как избежать:

1. Если нет жёсткой необходимости в UUID — не используй их как PK
2. Нужен UUID? Сделай его вторичным индексом, а PK оставь автоинкрементным
3. Или хотя бы используй UUID v7 (новый стандарт с time-based префиксом) — он улучшает локальность по сравнению с v4

Пример:


CREATE TABLE users (
id BIGSERIAL PRIMARY KEY,
public_id UUID DEFAULT gen_random_uuid() UNIQUE,
name TEXT
);


→ Внутри БД — быстрый BIGINT,
→ Для внешних API — UUID. Удобно и производительно.


📲 Мы в MAX

#db

👉 @database_info
👍5
This media is not supported in your browser
VIEW IN TELEGRAM
Хотите узнать секрет оптимизации SQL-запросов?

Очень важно понимать порядок выполнения.
В SQL-запросе операторы выполняются в следующем порядке:

1. FROM / JOIN
2. WHERE
3. GROUP BY
4. HAVING
5. SELECT
6. DISTINCT
7. ORDER BY
8. LIMIT / OFFSET

📲 Мы в MAX

#db

👉 @database_info
👍2🔥1
Как упростить работу с кластером через веб‑интерфейс OpenSearch Dashboards

Присоединяйтесь к вебинару от Selectel, чтобы разобраться на практике, как развернуть кластер СУБД OpenSearch в облаке за несколько минут и управлять им с помощью веб-интерфейса OpenSearch Dashboards. Узнаете, как легко настроить мониторинг, визуализировать данные и метрики, работать с бэкапами, управлять пользователями и доступами.

📍 Онлайн
⏰ 16 июля в 15:00
👤 Кому будет полезно: сисадминам, архитекторам, администраторам баз данных, бэкэнд-разработчикам, техлидам


Регистрируйтесь ➡️ https://slc.tl/3po0z

Больше мероприятий для ИТ-специалистов в канале @selectel_events. Подписывайтесь!

Реклама. АО "Селектел". erid:2W5zFK5Svmo
❤1
Индексы в PostgreSQL: Часть 1 — B-Tree

Если ты создавал индекс в PostgreSQL по умолчанию, значит, это B-Tree.
Но как он работает и когда он реально полезен?

Что это такое?

B-Tree индекс — сбалансированное дерево поиска.
PostgreSQL автоматически использует его для:

=\` (равенство)
> < >= <= (сравнения)
BETWEEN
LIKE 'abc%' (только префикс, без %abc%).

Пример:


CREATE INDEX idx_users_email ON users (email);
SELECT * FROM users WHERE email = 'test@example.com';


Запрос не будет сканировать всю таблицу — он сразу пойдёт по дереву.

Подводные камни:

1. Не работает для произвольных LIKE:
LIKE '%abc%' → индекс не поможет.
2. Осторожно с функциями:
WHERE LOWER(email) = 'abc' — индекс не используется. Нужен функциональный индекс:


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

3. Многоколонковые индексы:
Порядок важен. (a, b) используется при фильтре по a или по a AND b, но не только по b.

Когда ставить?

- Уникальные поля (email, username).
- Часто используемые фильтры и JOIN-колонки.
- Сортировки (ORDER BY created_at DESC).

Вывод:
B-Tree — твой “универсальный солдат”. Но не пихай его на всё подряд. Перед добавлением — смотри EXPLAIN (ANALYZE).

Сохрани, чтобы не забыть!

📲 Мы в MAX

#db

👉 @database_info
👍4🔥1
🔒 Почему одна "невинная" транзакция может положить продакшн

Классическая ситуация: разработчик открывает транзакцию, делает выборку, потом какой-то API-запрос наружу (например, к платёжному шлюзу), и только потом коммитит. Транзакция висит открытой 3-5 секунд вместо миллисекунд. Локально всё ок, тесты зелёные. В проде — деградация через пару часов.

Что происходит под капотом в PostgreSQL (MVCC):

1. VACUUM не может убрать мёртвые строки. Пока жива хоть одна старая транзакция, движок обязан хранить все версии строк, которые теоретически могут быть видны в её snapshot. UPDATE/DELETE копится в виде dead tuples, автовакуум работает, но эффективность падает.

2. Table bloat. Таблица физически растёт, индексы разбухают, страницы всё реже помещаются в shared_buffers — растёт I/O, падает cache hit ratio.

3. xmin horizon не двигается. Это глобальная граница, до которой можно чистить старые версии. Одна зависшая транзакция держит её на месте для ВСЕЙ базы, а не только для своей таблицы.

4. Реплики страдают отдельно. На hot standby с hot_standby_feedback = on долгая транзакция на реплике заставляет primary тоже не вакуумить нужные строки — эффект расползается по кластеру.

Как ловить:


SELECT pid, now() - xact_start AS duration, query
FROM pg_stat_activity
WHERE state != 'idle'
ORDER BY duration DESC
LIMIT 10;


Плюс idle in transaction — отдельная категория боли: транзакция открыта, а коннекшен вообще ничего не делает (забыли закоммитить/роллбэкнуть). Лечится через idle_in_transaction_session_timeout.

Правило для сеньора: транзакция должна жить ровно столько, сколько нужно для консистентности данных — не больше. Любой сетевой вызов, любая тяжёлая бизнес-логика — только вне транзакции или в отдельном коротком шаге.

#postgresql #databases #mvcc

📲 Мы в MAX

#db

👉 @database_info
👍5🔥1
This media is not supported in your browser
VIEW IN TELEGRAM
Чем отличаются друг от друга блокировки баз данных?

В управлении базами данных блокировки — это механизмы, которые предотвращают одновременный доступ к данным, обеспечивая их целостность и согласованность.

Основные типы блокировок:

🔴Shared Lock: позволяет нескольким транзакциям одновременно читать ресурс, но не модифицировать его
🔴Exclusive Lock: позволяет транзакции как читать, так и модифицировать ресурс
🔴 Update Lock: используется для предотвращения взаимоблокировки, когда транзакция намеревается обновить ресурс
🔴 Schema Lock: используется для защиты структуры объектов базы данных
🔴 Bulk Update Lock: используется во время массовых вставок
🔴 Key-Range Lock: используется в индексированных данных для предотвращения фантомных чтений
🔴 Row-Level Lock: блокирует конкретную строку в таблице
🔴 Page-Level Lock: блокирует конкретную страницу (фиксированный блок данных) в базе данных
🔴 Table-Level Lock: блокирует всю таблицу

📲 Мы в MAX

#db

👉 @database_info
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥4👍3
Почему Redis такой быстрый (несмотря на однопоточность)?

🔹 Хранение в памяти
Redis хранит все данные в оперативной памяти, где время доступа измеряется наносекундами, а не миллисекундами.

🔹 Однопоточный цикл событий
Redis обрабатывает команды в одном потоке, избегая блокировок, гонок и переключений контекста. Благодаря мультиплексированию ввода-вывода он эффективно обслуживает тысячи одновременных подключений через цикл событий.

🔹 Оптимизированные структуры данных
Redis предоставляет специализированные реализации списков, множеств, отсортированных множеств и хешей, оптимизированные для производительности и экономии памяти.

🔹 Эффективность ввода-вывода
Redis использует лёгкий текстовый протокол RESP для обработки сетевого I/O и поддерживает конвейеризацию, позволяя клиентам отправлять несколько команд в одном запросе.

🔹 Скрипты на стороне сервера
Встроенный движок Lua даёт возможность выполнять сложные многошаговые операции атомарно на сервере, убирая необходимость лишних сетевых запросов.

♻️ Сделай репост, чтобы помочь другим.

📲 Мы в MAX

#db

👉 @database_info
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4❤1🔥1
Почему индекс в PostgreSQL не всегда спасает

Индексы - мощный инструмент, но не панацея. Иногда запрос с индексом работает медленнее, чем без него. Почему?

1️⃣ Маленькая выборка - да, полное сканирование - нет
Если таблица маленькая (до нескольких тысяч строк), PostgreSQL может решить, что быстрее прочитать всё целиком, чем прыгать по индексу.


EXPLAIN ANALYZE
SELECT * FROM users WHERE status = 'active';


План покажет Seq Scan, и это не баг.

2️⃣ Индекс не помогает с функциями в WHERE
Запрос вида:


SELECT * FROM orders WHERE DATE(created_at) = '2025-08-12';


не использует индекс по created_at. Решение — переписать условие:


WHERE created_at >= '2025-08-12' AND created_at < '2025-08-13'


3️⃣ Селективность
Если по условию отбирается больше ~5–10% строк, индекс становится невыгодным — чтение с диска и так почти сплошное.

4️⃣ Статистика устарела
PostgreSQL выбирает план по статистике. Если она старая - план может быть неэффективным.


ANALYZE table_name;


- и жизнь наладится.

💡 Вывод: Индекс - не магическая кнопка «ускорить». Следи за планами запросов (EXPLAIN), обновляй статистику и оптимизируй условия.

Сохрани, чтобы не наступить на этот грабельный индекс 🚀

📲 Мы в MAX

#db

👉 @database_info
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6🔥3❤1
🗄 Нормализация баз данных: от 1NF до 4NF

Нормализация помогает правильно организовать данные, избавиться от дублирования и снизить риск ошибок при обновлении таблиц.

🔹 Первая нормальная форма — 1NF
Каждая ячейка содержит только одно атомарное значение. Нельзя хранить несколько товаров в одном поле — каждый товар должен находиться в отдельной строке.

🔹 Вторая нормальная форма — 2NF
Таблица соответствует 1NF, а каждый неключевой столбец полностью зависит от всего составного первичного ключа. Данные о заказе и его позициях обычно разделяются на разные таблицы.

🔹 Третья нормальная форма — 3NF
Устраняются транзитивные зависимости. Например, имя и регион клиента лучше хранить в таблице клиентов, а в заказе оставить только идентификатор клиента.

🔹 Нормальная форма Бойса — Кодда, BCNF
Усиленная версия 3NF: любой столбец, от которого зависят другие данные, должен быть потенциальным ключом.

🔹 Четвёртая нормальная форма — 4NF
Устраняет независимые многозначные зависимости. Например, навыки сотрудника и его проекты следует хранить в отдельных таблицах.

✅ Результат нормализации — меньше дубликатов, проще обновление данных и более предсказуемая работа базы.

А до какой нормальной формы вы обычно доводите структуру БД?

#базыданных #SQL #нормализация #database #программирование #разработка


📲 Мы в MAX

👉 @database_info
👍4🔥4❤1
Антипаттерны JOIN-ов в SQL и как их избежать

JOIN - мощная штука, но может легко превратиться в генератор тормозов и дублей. Вот топ-4 ловушек:

1️⃣ Забыли условие соединения


SELECT *
FROM orders
JOIN customers;


Без ON это картезианское произведение - каждая строка первой таблицы умножается на все строки второй. Легко получить миллионы ненужных записей.
✅ Как избежать: Всегда указывай условие соединения.


2️⃣ JOIN по неиндексированным колонкам
Если соединяешь большие таблицы по полю без индекса - готовься ждать.
✅ Как избежать: Добавь индекс на ключи соединения.


CREATE INDEX idx_orders_customer_id ON orders(customer_id);



3️⃣ Фильтры в WHERE вместо ON


-- Плохо
FROM orders
LEFT JOIN customers ON orders.customer_id = customers.id
WHERE customers.region = 'EU';


LEFT JOIN превратился в INNER JOIN, потому что фильтр в WHERE отсекает NULL-строки.
✅ Как избежать: Фильтруй в ON, если хочешь сохранить LEFT JOIN:


LEFT JOIN customers
ON orders.customer_id = customers.id AND customers.region = 'EU';



4️⃣ SELECT *** в сложных JOIN-ах
Такая выборка тянет все колонки всех таблиц. Много лишних данных + риск коллизии имён колонок.
✅ Как избежать: Явно указывай нужные поля.


💡 Вывод: JOIN - как скальпель. В умелых руках ускоряет, в неумелых - режет производительность.

Сохрани, чтобы не резануть базу не туда ✂️

📲 Мы в MAX

#db

👉 @database_info
👍7🔥3
Media is too big
VIEW IN TELEGRAM
7 обязательных стратегий для масштабирования вашей базы данных

📲 Мы в MAX

#db

👉 @database_info
👍2🔥2
💡 Универсальная шпаргалка по SQL

📲 Мы в MAX

#db

👉 @database_info
🔥4👍1