🔗 Мини-гайд по JOIN-ам в SQL
🔸 INNER JOIN
Что делает: оставляет только совпадающие строки из обеих таблиц.
Когда использовать: когда нужны только те записи, у которых есть соответствие.
🧠 Best practice: это дефолтный выбор. Работает быстрее, т.к. отбрасывает всё "лишнее".
🔸 LEFT JOIN
Что делает: возвращает все строки из левой таблицы и
Когда использовать: когда нужно сохранить всё из первой таблицы, даже если во второй нет данных.
🧠 Часто используется для аналитики: "у каких клиентов не было заказов?"
🔸 RIGHT JOIN
Что делает: наоборот — всё из правой таблицы и
Когда использовать: аналогично
🔸 FULL OUTER JOIN
Что делает: объединяет
Когда использовать: когда важны все данные, даже без соответствий.
🧠 Подходит для reconciliation'а или сверки.
❗ Совет
Фильтры (
Используй
Сохрани, чтобы не забыть. А ты какой JOIN используешь чаще всего?
📲 Мы в MAX
#db
👉 @database_info
JOIN — мощнейший инструмент в арсенале SQL. Но многие путаются в типах. Разбираем на пальцах:🔸 INNER JOIN
Что делает: оставляет только совпадающие строки из обеих таблиц.
Когда использовать: когда нужны только те записи, у которых есть соответствие.
SELECT *
FROM orders o
INNER JOIN customers c ON o.customer_id = c.id;
🧠 Best practice: это дефолтный выбор. Работает быстрее, т.к. отбрасывает всё "лишнее".
🔸 LEFT JOIN
Что делает: возвращает все строки из левой таблицы и
NULL из правой, если нет совпадения.Когда использовать: когда нужно сохранить всё из первой таблицы, даже если во второй нет данных.
SELECT *
FROM customers c
LEFT JOIN orders o ON o.customer_id = c.id;
🧠 Часто используется для аналитики: "у каких клиентов не было заказов?"
🔸 RIGHT JOIN
Что делает: наоборот — всё из правой таблицы и
NULL из левой, если нет совпадения.Когда использовать: аналогично
LEFT JOIN, но редко встречается, потому что просто меняем порядок таблиц.🔸 FULL OUTER JOIN
Что делает: объединяет
LEFT и RIGHT — берёт всё из обеих таблиц.Когда использовать: когда важны все данные, даже без соответствий.
SELECT *
FROM table_a
FULL OUTER JOIN table_b ON table_a.id = table_b.id;
🧠 Подходит для reconciliation'а или сверки.
❗ Совет
Фильтры (
WHERE) после LEFT JOIN могут не дать ожидаемый результат.Используй
ON для условий соединения, WHERE — для фильтрации результата.Сохрани, чтобы не забыть. А ты какой JOIN используешь чаще всего?
📲 Мы в MAX
#db
👉 @database_info
❤4👍3👎1
🧱 Антипаттерн: Ненормализованная схема в SQL
Когда нужно «быстро запилить фичу», руки тянутся сделать одну таблицу, где и заказ, и клиент, и товары — всё в куче.
Пример:
😰 Что пойдет не так:
– Дублирование данных — имя клиента повторяется в каждом заказе.
– Нет масштабируемости — максимум 2 продукта? А если будет 3?
– Трудности с запросами — попробуй посчитать топ-5 товаров. Удачи.
– Адские апдейты — изменить email клиента надо во всех заказах.
✅ Как правильно:
1. Нормализуй. Раздели данные на сущности:
2. Используй внешние ключи.
3. Не бойся JOIN'ов — они для этого и придуманы.
Пример нормализованной структуры:
📌 Да, нормализация требует чуть больше времени. Зато потом вы не утонете в хаосе.
Сохрани, чтобы не забыть — и не повторять чужих ошибок.
📲 Мы в MAX
#db
👉 @database_info
Когда нужно «быстро запилить фичу», руки тянутся сделать одну таблицу, где и заказ, и клиент, и товары — всё в куче.
Пример:
CREATE TABLE orders (
order_id SERIAL PRIMARY KEY,
customer_name TEXT,
customer_email TEXT,
product_1_name TEXT,
product_1_price NUMERIC,
product_2_name TEXT,
product_2_price NUMERIC
);
😰 Что пойдет не так:
– Дублирование данных — имя клиента повторяется в каждом заказе.
– Нет масштабируемости — максимум 2 продукта? А если будет 3?
– Трудности с запросами — попробуй посчитать топ-5 товаров. Удачи.
– Адские апдейты — изменить email клиента надо во всех заказах.
✅ Как правильно:
1. Нормализуй. Раздели данные на сущности:
customers, orders, products, order_items.2. Используй внешние ключи.
3. Не бойся JOIN'ов — они для этого и придуманы.
Пример нормализованной структуры:
-- Таблица клиентов
CREATE TABLE customers (
id SERIAL PRIMARY KEY,
name TEXT,
email TEXT
);
-- Таблица заказов
CREATE TABLE orders (
id SERIAL PRIMARY KEY,
customer_id INT REFERENCES customers(id)
);
-- Таблица товаров
CREATE TABLE products (
id SERIAL PRIMARY KEY,
name TEXT,
price NUMERIC
);
-- Связка товаров и заказов
CREATE TABLE order_items (
order_id INT REFERENCES orders(id),
product_id INT REFERENCES products(id),
quantity INT
);
📌 Да, нормализация требует чуть больше времени. Зато потом вы не утонете в хаосе.
Сохрани, чтобы не забыть — и не повторять чужих ошибок.
📲 Мы в MAX
#db
👉 @database_info
👍5❤2🔥1
Мини-гайд: Как ускорить SELECT’ы в PostgreSQL с помощью покрытия индекса (covering index)
Иногда индекс есть, а запрос всё равно тормозит. Почему?
👉 Потому что обычный индекс помогает найти строку, но потом БД всё равно лезет в таблицу, чтобы достать нужные поля. Это называется heap access — и это дорого.
📌 Решение — покрывающий индекс. Это индекс, который содержит все нужные поля прямо в себе. PostgreSQL с версии 11 умеет делать это через
🔧 Пример:
✅ Теперь PostgreSQL может ответить на запрос только по индексу, не трогая таблицу → быстрее.
📈 Особенно заметный профит:
– На больших таблицах
– В OLTP-нагрузках (много коротких запросов)
– Когда важна задержка ответа (например, API)
⚠️ Но не стоит включать весь ряд в индекс — это увеличит размер и замедлит обновления.
Вывод:
Покрывающие индексы — мощный способ ускорить SELECT без изменения запроса. Используй их там, где читаешь часто, а пишешь редко.
Сохрани, пригодится при оптимизации ⚙️
📲 Мы в MAX
#db
👉 @database_info
Иногда индекс есть, а запрос всё равно тормозит. Почему?
👉 Потому что обычный индекс помогает найти строку, но потом БД всё равно лезет в таблицу, чтобы достать нужные поля. Это называется heap access — и это дорого.
📌 Решение — покрывающий индекс. Это индекс, который содержит все нужные поля прямо в себе. PostgreSQL с версии 11 умеет делать это через
INCLUDE.🔧 Пример:
-- Запрос
SELECT name, email FROM users WHERE status = 'active';
-- Обычный индекс
CREATE INDEX idx_users_status ON users(status);
-- Покрывающий индекс
CREATE INDEX idx_users_status_cover ON users(status) INCLUDE (name, email);
✅ Теперь PostgreSQL может ответить на запрос только по индексу, не трогая таблицу → быстрее.
📈 Особенно заметный профит:
– На больших таблицах
– В OLTP-нагрузках (много коротких запросов)
– Когда важна задержка ответа (например, API)
⚠️ Но не стоит включать весь ряд в индекс — это увеличит размер и замедлит обновления.
Вывод:
Покрывающие индексы — мощный способ ускорить SELECT без изменения запроса. Используй их там, где читаешь часто, а пишешь редко.
Сохрани, пригодится при оптимизации ⚙️
📲 Мы в MAX
#db
👉 @database_info
👍10❤3
💣 NULL — тихий саботаж в твоей БД
На первый взгляд,
📉 Антипаттерн: беспечное обращение с NULL
Примеры:
Ты думаешь, что отбираешь всех взрослых, но
🙈 Проблема:
📉 Итоги: ошибки в JOIN'ах, WHERE-фильтрах, расчетах.
🛡 Как защититься:
✅ Явно учитывай
✅ Используй
✅ Проверяй
✅ Для агрегаций учитывай поведение
Вывод:
Пиши запросы так, как будто
Сохрани, чтобы не ловить грабли 💥
📲 Мы в MAX
#db
👉 @database_info
На первый взгляд,
NULL — просто отсутствие значения. Но на практике это частый источник багов, неверных аналитик и проблем в бизнес-логике.📉 Антипаттерн: беспечное обращение с NULL
Примеры:
SELECT * FROM users WHERE age > 18; -- Пользователи с age = NULL не попадут
Ты думаешь, что отбираешь всех взрослых, но
age = NULL тут "выпадает", ведь NULL > 18 → UNKNOWN.
WHERE col1 = col2 -- Не сработает, если хотя бы одно значение NULL
🙈 Проблема:
NULL не равно даже самому себе (NULL != NULL).📉 Итоги: ошибки в JOIN'ах, WHERE-фильтрах, расчетах.
🛡 Как защититься:
✅ Явно учитывай
NULL:
WHERE age > 18 OR age IS NULL -- если хочешь включить "неизвестный возраст"
✅ Используй
COALESCE:
SELECT COALESCE(discount, 0) FROM orders -- подставим 0, если скидка не указана
✅ Проверяй
NULL через IS NULL / IS NOT NULL✅ Для агрегаций учитывай поведение
NULL:
AVG(column) -- пропустит NULL'ы, но COUNT(column) тоже не посчитает их!
Вывод:
NULL — не "ничего", а "неизвестно".Пиши запросы так, как будто
NULL всегда где-то прячется — и он не на твоей стороне.Сохрани, чтобы не ловить грабли 💥
📲 Мы в MAX
#db
👉 @database_info
👍14❤5
Разбор кейса. Компания переехала с MongoDB на PostgreSQL - зачем и что пошло не так.
Стартап хранил всё в MongoDB — быстро, удобно, JSON-документы летят.
Но через год — бизнес растёт, появляются проблемы:
🔸 Запросы тормозят.
Mongo не любит сложные агрегаты с джойнами по коллекциям.
А бизнесу уже нужно:
– аналитика по заказам
– ретеншн-отчёты
– CRM-связи между сущностями
🔸 Дублирование данных.
Документы растут, становятся вложенными, обновлять — боль.
Классическая проблема: “Обновили e-mail юзера — забыли в двух местах”.
🔸 Сложность поддержки.
Без схемы трудно отследить, что где лежит. Новым разработчикам — боль.
🔁 Решение: PostgreSQL
– Явная схема → валидируем данные сразу
– Поддержка JSONB → можно переехать частями
– Сильный SQL → отчёты, джойны, агрегации — на ура
– Надёжность и mature-инструменты для миграций, бэкапов, мониторинга
⚠️ Подводные камни:
– Миграция данных: пришлось писать парсеры и валидаторы
– Пришлось переосмыслить структуру: из “гибкого” хаоса в нормализованную модель
– Команда училась писать SQL и настраивать индексы
✅ Зато теперь:
– Запросы летят
– Данные валидны
– Аналитика возможна
– Рост — без боли
Переход с NoSQL на SQL — это не “откат назад”, это осознанный апгрейд, когда бизнесу нужен контроль, скорость и предсказуемость.
📲 Мы в MAX
#db
👉 @database_info
Стартап хранил всё в MongoDB — быстро, удобно, JSON-документы летят.
Но через год — бизнес растёт, появляются проблемы:
🔸 Запросы тормозят.
Mongo не любит сложные агрегаты с джойнами по коллекциям.
А бизнесу уже нужно:
– аналитика по заказам
– ретеншн-отчёты
– CRM-связи между сущностями
🔸 Дублирование данных.
Документы растут, становятся вложенными, обновлять — боль.
Классическая проблема: “Обновили e-mail юзера — забыли в двух местах”.
🔸 Сложность поддержки.
Без схемы трудно отследить, что где лежит. Новым разработчикам — боль.
🔁 Решение: PostgreSQL
– Явная схема → валидируем данные сразу
– Поддержка JSONB → можно переехать частями
– Сильный SQL → отчёты, джойны, агрегации — на ура
– Надёжность и mature-инструменты для миграций, бэкапов, мониторинга
⚠️ Подводные камни:
– Миграция данных: пришлось писать парсеры и валидаторы
– Пришлось переосмыслить структуру: из “гибкого” хаоса в нормализованную модель
– Команда училась писать SQL и настраивать индексы
✅ Зато теперь:
– Запросы летят
– Данные валидны
– Аналитика возможна
– Рост — без боли
Переход с NoSQL на SQL — это не “откат назад”, это осознанный апгрейд, когда бизнесу нужен контроль, скорость и предсказуемость.
📲 Мы в MAX
#db
👉 @database_info
👍10❤2🔥1
PostgreSQL: архитектура и тюнинг SQL-запросов
Погрузись в архитектуру и прокачай оптимизацию запросов одной из самых популярных open source СУБД – PostgreSQL.
🌐 В программе курса:
🤩 Разберем, как работают СУБД вообще и PostgreSQL в частности: что такое MVCC, ACID, WAL, LRU, PPC/TPC и другие фундаментальные понятия архитектуры баз данных
🤩 Получите теорию и практику EXPLAIN и EXPLAIN ANALYZE на разных типа запросов: без индексов, с индексами, index only, нормализованные и документ-ориентированные данные и json-поля, изменение параметров сессии/конфигурации для ускорения запросов
🤩 Изучите архитектуру хранения данных в PostgreSQL, типы и особенности индексов, а также получите полезные советы и трюки оптимизации БД
🤩 Получите свой собственный выделенный облачный PostgreSQL-сервер (8 vCPU, 12G RAM, 100G NVMe) – предоставляется БЕСПЛАТНО на время обучения + готовый e-commerce датасет TPC-H (миллион пользователей, несколько миллионов заказов на десятки гигабайт)
🗓 Старт курса: 22 января. 5 недель обучения.
Изучить программу и записаться можно здесь.
🤩 Кто мы: R&D-центр Devhands, основатель школы Алексей Рыбак. Автор курса — Николай Ихалайнен, эксперт по СУБД (ex-Percona), со-основатель MyDB, энтузиаст открытого ПО.
Реклама. ИП Рыбак А.А. ИНН 771407709607 Erid: 2VtzqwXjZhV
Погрузись в архитектуру и прокачай оптимизацию запросов одной из самых популярных open source СУБД – PostgreSQL.
Изучить программу и записаться можно здесь.
Реклама. ИП Рыбак А.А. ИНН 771407709607 Erid: 2VtzqwXjZhV
Please open Telegram to view this post
VIEW IN TELEGRAM
❤6🔥4👍3
PostgreSQL или MySQL?
Один из самых частых вопросов от разработчиков и DevOps - “Что лучше: PostgreSQL или MySQL?”. Давай без фанатизма, просто по фактам 👇
🔷 PostgreSQL:
🔵 Поддержка JSONB с индексами - почти как NoSQL внутри SQL
🔵 CTE, оконные функции, полнотекстовый поиск - топ для аналитики
🔵 Расширяемость: можно писать свои типы, функции, операторы
🔵 Хорош для сложных запросов, аналитики, геоданных (PostGIS)
🔻 Минусы:
– Сложнее в настройке и оптимизации
– Меньше хостингов out-of-the-box (но всё быстро меняется)
🔶 MySQL (особенно InnoDB / MariaDB):
🔵 Быстрее на простых SELECT/INSERT, если запросы примитивные
🔵 Больше ready-to-go хостингов и тулов для web
🔵 Низкий порог входа - быстрее поднимается новичками
🔻 Минусы:
– Слабее в сложных SQL-конструкциях
– Нет нормальной поддержки CTE до недавнего времени
– JSON без индексации (в MySQL < 8.0)
Вывод:
🧠 Если делаешь CRM, веб-продукт или MVP с простыми запросами, MySQL зайдёт.
📊 Если строишь data-heavy приложения, BI, ETL или гео-системы, PostgreSQL без шансов.
📲 Мы в MAX
#db
👉 @database_info
Один из самых частых вопросов от разработчиков и DevOps - “Что лучше: PostgreSQL или MySQL?”. Давай без фанатизма, просто по фактам 👇
🔷 PostgreSQL:
🔻 Минусы:
– Сложнее в настройке и оптимизации
– Меньше хостингов out-of-the-box (но всё быстро меняется)
🔶 MySQL (особенно InnoDB / MariaDB):
🔻 Минусы:
– Слабее в сложных SQL-конструкциях
– Нет нормальной поддержки CTE до недавнего времени
– JSON без индексации (в MySQL < 8.0)
Вывод:
🧠 Если делаешь CRM, веб-продукт или MVP с простыми запросами, MySQL зайдёт.
📊 Если строишь data-heavy приложения, BI, ETL или гео-системы, PostgreSQL без шансов.
📲 Мы в MAX
#db
👉 @database_info
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5👌2🔥1
🛑 Антипаттерн: "Списки через запятую" в базе данных
Признайтесь, у каждого был соблазн сделать это. У вас есть сущность (например,
В БД это выглядит так:
Почему это бомба замедленного действия и как это лечить? Давайте разбираться.
Почему это плохо (The Pain):
1. Сложный поиск. Найти всех пользователей с
2. Никаких индексов. База данных не может эффективно индексировать подстроки в таком формате. Full scan обеспечен.
3. Проблемы с JOIN. Вы не сможете сделать нормальный
4. Целостность данных. Вы не можете повесить Foreign Key. Никто не помешает записать туда
5. Атомарность обновлений. Удалить роль
Как делать правильно:
Вариант 1: Классическая нормализация (Junction Table)
Создайте связующую таблицу. Это золотой стандарт для реляционных БД (PostgreSQL, MySQL, Oracle).
Теперь выборка всех админов - это моментальный запрос с использованием индексов.
Вариант 2: Массивы или JSONB (PostgreSQL)
Если вы используете PostgreSQL и вам действительно не нужны жесткие FK (Foreign Keys) на каждый элемент, можно использовать нативные типы.
Никогда не храните списки в
Сталкивались с таким в легаси-коде? Пишите в комменты 👇
📲 Мы в MAX
#db
👉 @database_info
Признайтесь, у каждого был соблазн сделать это. У вас есть сущность (например,
User), и нужно сохранить список их ролей или IDs купленных товаров. Создавать отдельную таблицу кажется оверхедом, и вы решаете: "А, запишу просто строкой через запятую".В БД это выглядит так:
role_ids: "1,4,12"Почему это бомба замедленного действия и как это лечить? Давайте разбираться.
Почему это плохо (The Pain):
1. Сложный поиск. Найти всех пользователей с
role_id = 1 через LIKE '%1%' - это больно. Вы найдете и 1, и 12, и 100. Придется писать монструозные регулярки.2. Никаких индексов. База данных не может эффективно индексировать подстроки в таком формате. Full scan обеспечен.
3. Проблемы с JOIN. Вы не сможете сделать нормальный
JOIN с таблицей ролей.4. Целостность данных. Вы не можете повесить Foreign Key. Никто не помешает записать туда
"1, 4, apple, NULL".5. Атомарность обновлений. Удалить роль
4 из строки "1,4,12" - это чтение, парсинг на бекенде и перезапись. Состояние гонки (race condition) гарантировано.Как делать правильно:
Вариант 1: Классическая нормализация (Junction Table)
Создайте связующую таблицу. Это золотой стандарт для реляционных БД (PostgreSQL, MySQL, Oracle).
-- Плохо ❌
CREATE TABLE users (
id INT PRIMARY KEY,
name VARCHAR(50),
role_ids VARCHAR(255) -- "1,2"
);
-- Хорошо ✅
CREATE TABLE user_roles (
user_id INT,
role_id INT,
PRIMARY KEY (user_id, role_id),
FOREIGN KEY (user_id) REFERENCES users(id),
FOREIGN KEY (role_id) REFERENCES roles(id)
);
Теперь выборка всех админов - это моментальный запрос с использованием индексов.
Вариант 2: Массивы или JSONB (PostgreSQL)
Если вы используете PostgreSQL и вам действительно не нужны жесткие FK (Foreign Keys) на каждый элемент, можно использовать нативные типы.
-- Допустимо в Postgres ✅
CREATE TABLE users (
id SERIAL PRIMARY KEY,
name TEXT,
role_ids INT[] -- массив целых чисел
);
-- Поиск (очень быстрый с GIN индексом):
SELECT * FROM users WHERE 1 = ANY(role_ids);
Никогда не храните списки в
VARCHAR, если вам когда-либо придется искать по содержимому этого списка или джойнить его. Экономия 5 минут на старте обернется часами рефакторинга позже.Сталкивались с таким в легаси-коде? Пишите в комменты 👇
📲 Мы в MAX
#db
👉 @database_info
👍6❤4
Антипаттерн:
Использовать
Почему это плохо:
🔹 Излишняя нагрузка на сеть и СУБД - выбираются все столбцы, включая ненужные.
🔹 Проблемы с индексами - СУБД может не использовать покрывающий индекс.
🔹 Ломается при изменении схемы - добавил столбец → внезапно изменилось поведение приложения.
🔹 Сложнее читать и поддерживать - особенно в JOIN’ах.
✅ Как правильно:
Запрашивай только нужные поля:
📌 И даже в админках/аналитике лучше явно указывать поля - это дисциплинирует.
Хочешь писать код, который легко масштабировать и отлаживать - забудь про
Сохрани, чтобы не забыть 💾
Поделись с коллегами, которые всё ещё "звёздят" в SQL ✨
📲 Мы в MAX
#db
👉 @database_info
SELECT * - удобно, но опасноИспользовать
SELECT * - значит звать всех на вечеринку, даже если звал только двоих.Почему это плохо:
🔹 Излишняя нагрузка на сеть и СУБД - выбираются все столбцы, включая ненужные.
🔹 Проблемы с индексами - СУБД может не использовать покрывающий индекс.
🔹 Ломается при изменении схемы - добавил столбец → внезапно изменилось поведение приложения.
🔹 Сложнее читать и поддерживать - особенно в JOIN’ах.
✅ Как правильно:
Запрашивай только нужные поля:
SELECT id, name, created_at FROM users;
📌 И даже в админках/аналитике лучше явно указывать поля - это дисциплинирует.
Хочешь писать код, который легко масштабировать и отлаживать - забудь про
SELECT *.Сохрани, чтобы не забыть 💾
Поделись с коллегами, которые всё ещё "звёздят" в SQL ✨
📲 Мы в MAX
#db
👉 @database_info
👍8
🔧 Mini-гайд: ускоряем JOIN-ы в больших таблицах
JOIN-ы - мощный инструмент SQL, но на больших объёмах данных могут стать узким горлышком. Вот 5 проверенных способов ускорить их:
1. Индексы по ключам соединения
Без индекса - каждый JOIN превращается в полный перебор.
➤ Пример:
2. Ограничь объём данных до JOIN-а
Фильтруй и агрегируй данные до объединения.
➤ Вместо:
➤ Лучше:
3. Учитывай тип JOIN-а
4. Следи за типами данных
5. Проверь планы выполнения (EXPLAIN)
Не гадай, а смотри, что реально происходит.
📌 Даже один лишний JOIN может уронить производительность. Внимательность + EXPLAIN = уверенность.
Поделись с коллегами - спасёшь чей-то прод.
📲 Мы в MAX
#db
👉 @database_info
JOIN-ы - мощный инструмент SQL, но на больших объёмах данных могут стать узким горлышком. Вот 5 проверенных способов ускорить их:
1. Индексы по ключам соединения
Без индекса - каждый JOIN превращается в полный перебор.
➤ Пример:
CREATE INDEX idx_user_id ON orders(user_id);
2. Ограничь объём данных до JOIN-а
Фильтруй и агрегируй данные до объединения.
➤ Вместо:
SELECT * FROM orders o JOIN users u ON o.user_id = u.id WHERE u.country = 'DE';
➤ Лучше:
WITH german_users AS (
SELECT id FROM users WHERE country = 'DE'
)
SELECT * FROM orders o JOIN german_users g ON o.user_id = g.id;
3. Учитывай тип JOIN-а
INNER JOIN обычно быстрее OUTER JOIN, особенно при наличии NOT NULL. Иногда EXISTS работает быстрее, чем LEFT JOIN.4. Следи за типами данных
JOIN по полям с разными типами (например, int и varchar) = неэффективный cast + тормоза.5. Проверь планы выполнения (EXPLAIN)
Не гадай, а смотри, что реально происходит.
EXPLAIN ANALYZE - твой друг.📌 Даже один лишний JOIN может уронить производительность. Внимательность + EXPLAIN = уверенность.
Поделись с коллегами - спасёшь чей-то прод.
📲 Мы в MAX
#db
👉 @database_info
👍9
❌ Антипаттерн: булевы значения как строки
В таблице
На первый взгляд — ерунда. На практике:
– нет валидации: можно вставить
– медленнее сравнение, чем у
– больше места в хранилище,
– сложно агрегировать и строить аналитику.
🔧 Как надо:
– Экономия места (1 байт против 5 и больше)
– Проверка через
– Простой
– Автоматическая поддержка в ORM и UI-форматах
📌 Даже если тебе нужно больше состояний - используй
💡Чем проще тип, тем меньше шансов на баг.
Сохрани, если в коде встречал такое - и переделай с чистой совестью.
📲 Мы в MAX
#db
👉 @database_info
В таблице
users встречал такое:
is_active VARCHAR(5) -- значения 'true' или 'false'
На первый взгляд — ерунда. На практике:
– нет валидации: можно вставить
'tru', 'yes', '0',– медленнее сравнение, чем у
BOOLEAN,– больше места в хранилище,
– сложно агрегировать и строить аналитику.
🔧 Как надо:
is_active BOOLEAN DEFAULT true
– Экономия места (1 байт против 5 и больше)
– Проверка через
WHERE is_active– Простой
COUNT(*) FILTER (WHERE is_active) для отчётов– Автоматическая поддержка в ORM и UI-форматах
📌 Даже если тебе нужно больше состояний - используй
ENUM, а не строку.💡Чем проще тип, тем меньше шансов на баг.
Сохрани, если в коде встречал такое - и переделай с чистой совестью.
📲 Мы в MAX
#db
👉 @database_info
👍10🔥1
Индексы в PostgreSQL: когда и как ставить, чтобы ускорить запросы
🔍 Что такое индекс?
Индекс в PostgreSQL - это структура данных (обычно B-tree), позволяющая быстро находить строки по значению столбца, не сканируя всю таблицу.
⚙️ Пример создания простого B-tree-индекса
✅ Best Practices
1. Выбирай правильный тип
🔹
🔹
🔹
2. Индексируй часто фильтруемые и сортируемые поля
🔹WHERE, JOIN, ORDER BY.
🔹Например, для запросов типа
создаём составной индекс:
3. Не злоупотребляй
🔹Каждый индекс занимает место и замедляет INSERT/UPDATE/DELETE.
🔹Проанализируй
4. Используй частичные индексы
Если условие фильтрации редко меняется, можно сузить индекс:
5. Поддерживай актуальность
Периодически делай
❌ Антипаттерн: “Индекс на всё”
Создание индекса на каждый столбец:
Проблемы:
🔹Большой объём хранилища.
🔹Замедление DML-операций.
🔹Планы запросов могут пропускать некоторые индексы.
💡 Вывод
Правильно подобранные и настроенные индексы - ключ к быстрой работе базы. Сосредоточься на реально востребованных столбцах, комбинируй, не забывай про обслуживание.
Сохрани этот мини-гайд, чтобы не забыть, и поделись с коллегами: какие индексы стали для тебя открытием?
📲 Мы в MAX
#db
👉 @database_info
🔍 Что такое индекс?
Индекс в PostgreSQL - это структура данных (обычно B-tree), позволяющая быстро находить строки по значению столбца, не сканируя всю таблицу.
⚙️ Пример создания простого B-tree-индекса
-- Ускоряем поиск по полю email
CREATE INDEX idx_users_email
ON users (email);
✅ Best Practices
1. Выбирай правильный тип
🔹
BTREE - по умолчанию, для большинства операций сравнения (=, <, >, BETWEEN).🔹
GIN/GiST - для полнотекстового поиска (tsvector), работы с массивами и геоданных.🔹
HASH - для строго равенств (=), но редко нужен.2. Индексируй часто фильтруемые и сортируемые поля
🔹WHERE, JOIN, ORDER BY.
🔹Например, для запросов типа
SELECT * FROM orders
WHERE user_id = 42
ORDER BY created_at DESC;
создаём составной индекс:
CREATE INDEX idx_orders_user_created
ON orders (user_id, created_at DESC);
3. Не злоупотребляй
🔹Каждый индекс занимает место и замедляет INSERT/UPDATE/DELETE.
🔹Проанализируй
pg_stat_user_indexes и pg_stat_user_tables через pg_stat_statements перед добавлением.4. Используй частичные индексы
Если условие фильтрации редко меняется, можно сузить индекс:
CREATE INDEX idx_active_users_email
ON users (email)
WHERE active = true;
5. Поддерживай актуальность
Периодически делай
REINDEX или VACUUM ANALYZE для больших таблиц, чтобы индекс не фрагментировался.❌ Антипаттерн: “Индекс на всё”
Создание индекса на каждый столбец:
-- Плохо: много маленьких индексов, мало пользы, много затрат
CREATE INDEX idx1 ON table(a);
CREATE INDEX idx2 ON table(b);
CREATE INDEX idx3 ON table(c);
...
Проблемы:
🔹Большой объём хранилища.
🔹Замедление DML-операций.
🔹Планы запросов могут пропускать некоторые индексы.
💡 Вывод
Правильно подобранные и настроенные индексы - ключ к быстрой работе базы. Сосредоточься на реально востребованных столбцах, комбинируй, не забывай про обслуживание.
Сохрани этот мини-гайд, чтобы не забыть, и поделись с коллегами: какие индексы стали для тебя открытием?
📲 Мы в MAX
#db
👉 @database_info
👍7
🔗 Сравнение: Типы JOIN в SQL и когда их применять
Зачем понимать JOIN’ы?
Правильный выбор типа соединения таблиц позволяет получать необходимые данные эффективно и избегать неожиданных «пустых» или дублирующихся строк.
1. Основные типы JOIN и их поведение
INNER JOIN Возвращает только строки, у которых есть совпадения в обеих таблицах. Когда нужно только пересечение данных.
LEFT JOIN Берёт все строки из левой таблицы и совпадающие из правой (NULL, если нет). Когда важно сохранить все данные «слева» даже без пары.
RIGHT JOIN Аналог LEFT, но берёт все из правой таблицы. Редко используется, чаще удобнее поменять местами таблицы.
FULL JOIN Объединяет LEFT и RIGHT: все строки из обеих таблиц, NULL там, где нет пары. Когда нужны все данные из обеих, и нет явного «лево/право».
CROSS JOIN Декартово произведение: каждая строка левой с каждой строкой правой. При генерации матриц или тестовых наборов.
2. Примеры синтаксиса
3. Лучшие практики и советы
1. Всегда уточняйте направление соединения
Понимайте, какая таблица «левее»: от этого зависит полнота результатов.
2. Используйте явный JOIN вместо «старого» синтаксиса через WHERE
Повышает читабельность и уменьшает риск ошибок.
3. Ограничивайте выборку
Добавляйте фильтры (
4. Проверяйте результаты на NULL
При LEFT/FULL JOIN обрабатывайте
4. Подводные камни
🔹Нежелательный CROSS JOIN
Пропущенный условный оператор соединения приведёт к взрывному росту строк.
🔹Производительность
JOIN’ы на больших таблицах без индексов по ключам могут быть медленными.
🔹Дублирование
Многократное соединение одной таблицы без корректных условий - источник «дублей».
Вывод: понимание семантики JOIN’ов - ключ к точной и быстрой выборке данных.
Сохрани себе, поделись с коллегами и напиши в комментариях: с каким типом JOIN у тебя чаще всего возникают вопросы?
📲 Мы в MAX
#db
👉 @database_info
Зачем понимать JOIN’ы?
Правильный выбор типа соединения таблиц позволяет получать необходимые данные эффективно и избегать неожиданных «пустых» или дублирующихся строк.
1. Основные типы JOIN и их поведение
INNER JOIN Возвращает только строки, у которых есть совпадения в обеих таблицах. Когда нужно только пересечение данных.
LEFT JOIN Берёт все строки из левой таблицы и совпадающие из правой (NULL, если нет). Когда важно сохранить все данные «слева» даже без пары.
RIGHT JOIN Аналог LEFT, но берёт все из правой таблицы. Редко используется, чаще удобнее поменять местами таблицы.
FULL JOIN Объединяет LEFT и RIGHT: все строки из обеих таблиц, NULL там, где нет пары. Когда нужны все данные из обеих, и нет явного «лево/право».
CROSS JOIN Декартово произведение: каждая строка левой с каждой строкой правой. При генерации матриц или тестовых наборов.
2. Примеры синтаксиса
-- INNER: только общие заказы и клиенты
SELECT o.id, c.name
FROM orders o
INNER JOIN customers c ON o.customer_id = c.id;
-- LEFT: все заказы, даже если клиента нет (NULL)
SELECT o.id, c.name
FROM orders o
LEFT JOIN customers c ON o.customer_id = c.id;
-- FULL: все заказы и все клиенты
SELECT o.id AS order_id, c.id AS customer_id
FROM orders o
FULL JOIN customers c ON o.customer_id = c.id;
3. Лучшие практики и советы
1. Всегда уточняйте направление соединения
Понимайте, какая таблица «левее»: от этого зависит полнота результатов.
2. Используйте явный JOIN вместо «старого» синтаксиса через WHERE
Повышает читабельность и уменьшает риск ошибок.
3. Ограничивайте выборку
Добавляйте фильтры (
WHERE, ON) до JOIN, чтобы не нагружать соединение лишними данными.4. Проверяйте результаты на NULL
При LEFT/FULL JOIN обрабатывайте
NULL через COALESCE или дополнительные условия.4. Подводные камни
🔹Нежелательный CROSS JOIN
Пропущенный условный оператор соединения приведёт к взрывному росту строк.
🔹Производительность
JOIN’ы на больших таблицах без индексов по ключам могут быть медленными.
🔹Дублирование
Многократное соединение одной таблицы без корректных условий - источник «дублей».
Вывод: понимание семантики JOIN’ов - ключ к точной и быстрой выборке данных.
Сохрани себе, поделись с коллегами и напиши в комментариях: с каким типом JOIN у тебя чаще всего возникают вопросы?
📲 Мы в MAX
#db
👉 @database_info
👍8❤2