Сегодня я хочу рассказать вам про одну часто недооцененную фишку в PostgreSQL — partial indexes (частичные индексы).
Обычно мы создаём индексы на всю таблицу, но что если нам нужно ускорить только небольшую часть данных? Например, часто выбираются только активные пользователи (
Что это даёт:
- Индекс меньше по размеру → быстрее поиск и обновление.
- Используется только тогда, когда запрос соответствует условию
- Меньше нагрузка на диск при обновлениях таблицы.
🛠 Где это реально помогает:
- Таблицы с миллионами записей, где активно работают только с частью строк.
- Сценарии "горячих" и "холодных" данных.
Рекомендую попробовать partial indexes там, где обычные индексы слишком тяжелы или тормозят обновления!
#db
👉 @database_info
Обычно мы создаём индексы на всю таблицу, но что если нам нужно ускорить только небольшую часть данных? Например, часто выбираются только активные пользователи (
status
= 'active'
). Вместо полного индекса можно создать индекс только для нужного поднабора данных:
CREATE INDEX idx_active_users
ON users (last_login)
WHERE status = 'active';
Что это даёт:
- Индекс меньше по размеру → быстрее поиск и обновление.
- Используется только тогда, когда запрос соответствует условию
status = 'active'
.- Меньше нагрузка на диск при обновлениях таблицы.
🛠 Где это реально помогает:
- Таблицы с миллионами записей, где активно работают только с частью строк.
- Сценарии "горячих" и "холодных" данных.
Рекомендую попробовать partial indexes там, где обычные индексы слишком тяжелы или тормозят обновления!
#db
👉 @database_info
👍14
🔎 Мини-гайд: Индексы в PostgreSQL — быстро и по делу
Индексы — главный инструмент для ускорения запросов. Но неправильное использование может только навредить.
Основные типы индексов в PostgreSQL:
-
-
-
-
-
Практические советы:
- Не злоупотребляй индексами: каждый индекс замедляет
- Следи за актуальностью: периодически проверяй и удаляй неиспользуемые (
- Составные индексы (
- Используй
Типичная ошибка:
Создать индекс на всё подряд без анализа запросов. Итог — тормоза на записи и огромный размер базы.
✅ Индексы — это как специи: мало — пресно, много — несъедобно.
Вывод:
Хотите быструю базу — планируйте индексацию так же внимательно, как сами запросы.
Сохрани, чтобы не забыть!
#db
👉 @database_info
Индексы — главный инструмент для ускорения запросов. Но неправильное использование может только навредить.
Основные типы индексов в PostgreSQL:
-
B-tree
— по умолчанию. Идеален для поиска по равенству и диапазону (=
, <
, >
, BETWEEN
).-
Hash
— только для поиска по точному равенству (=
). Становится актуальным реже.-
GIN
— для массивов, JSONB, полнотекстового поиска.-
GiST
— геоданные, поиск по диапазонам, сложные типы.-
BRIN
— для очень больших таблиц с упорядоченными данными (например, логи).Практические советы:
- Не злоупотребляй индексами: каждый индекс замедляет
INSERT/UPDATE/DELETE
.- Следи за актуальностью: периодически проверяй и удаляй неиспользуемые (
pg_stat_user_indexes
поможет).- Составные индексы (
(col1, col2)
) эффективны, только если условия WHERE учитывают порядок колонок.- Используй
EXPLAIN ANALYZE
, чтобы понять, работает ли индекс в реальности.Типичная ошибка:
Создать индекс на всё подряд без анализа запросов. Итог — тормоза на записи и огромный размер базы.
✅ Индексы — это как специи: мало — пресно, много — несъедобно.
Вывод:
Хотите быструю базу — планируйте индексацию так же внимательно, как сами запросы.
Сохрани, чтобы не забыть!
#db
👉 @database_info
👍14
❌ Антипаттерн: Хранить даты и время в
Встречали такое?
На первый взгляд — всё ок: дата есть, строка хранит. Но на практике — сплошные проблемы:
🔴 Нет гарантии формата
🔴 Сложность фильтрации и сортировки
Сравнение строк ≠ сравнение дат.
Запросы типа
🔴 Нельзя использовать функции времени
Ни
✅ Как правильно
Используйте типы
* валидируют данные на вставке;
* дают мощный инструментарий для анализа;
* упрощают работу с часовыми поясами и интервалами.
💡 Если данные приходят в виде строк — парси их при загрузке, а не храни как есть.
Сохрани, чтобы не наступить на эти же грабли ☝️
А как у вас хранят даты?
#db
👉 @database_info
VARCHAR
Встречали такое?
CREATE TABLE orders (
id SERIAL PRIMARY KEY,
order_date VARCHAR(20)
);
На первый взгляд — всё ок: дата есть, строка хранит. Но на практике — сплошные проблемы:
🔴 Нет гарантии формата
'2024-12-01'
, '12/01/2024'
, '01.12.24'
, 'вчера'
— всё ляжет, но работать с этим потом боль.🔴 Сложность фильтрации и сортировки
Сравнение строк ≠ сравнение дат.
Запросы типа
WHERE order_date > '2024-01-01'
могут вести себя непредсказуемо.🔴 Нельзя использовать функции времени
Ни
DATE_TRUNC
, ни AGE()
, ни агрегаты по времени не работают нормально с VARCHAR
.✅ Как правильно
Используйте типы
DATE
, TIMESTAMP
, TIMESTAMPTZ
— они:* валидируют данные на вставке;
* дают мощный инструментарий для анализа;
* упрощают работу с часовыми поясами и интервалами.
CREATE TABLE orders (
id SERIAL PRIMARY KEY,
order_date TIMESTAMPTZ DEFAULT now()
);
💡 Если данные приходят в виде строк — парси их при загрузке, а не храни как есть.
Сохрани, чтобы не наступить на эти же грабли ☝️
А как у вас хранят даты?
#db
👉 @database_info
👍12
📕MySQL для администраторов, разработчиков, архитекторов и специалистов баз данных
Как грамотно оптимизировать производительность в MySQL и решить возникающие проблемы.
📗 На вебинаре 6 мая в 19:00 разберём:
1. Практические методы оптимизации производительности, диагностику нагрузки и анализ "узких мест" MySQL;
2. Оптимизацию запросов: от простых до сложных.
📘 В результате будете знать всё о настройке ключевых параметров конфигурации, уметь самостоятельно диагностировать и решать проблемы производительности MySQL.
👉 Регистрация и подробности о курсе Базы данных: https://vk.cc/cLzQgf
Все участники открытого урока получат скидку на курс
Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576
Как грамотно оптимизировать производительность в MySQL и решить возникающие проблемы.
📗 На вебинаре 6 мая в 19:00 разберём:
1. Практические методы оптимизации производительности, диагностику нагрузки и анализ "узких мест" MySQL;
2. Оптимизацию запросов: от простых до сложных.
📘 В результате будете знать всё о настройке ключевых параметров конфигурации, уметь самостоятельно диагностировать и решать проблемы производительности MySQL.
👉 Регистрация и подробности о курсе Базы данных: https://vk.cc/cLzQgf
Все участники открытого урока получат скидку на курс
Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576
Антипаттерн: «Одна таблица на всё»
Когда бизнес-логика усложняется, а структура БД остаётся в духе Excel — жди беды.
🔴 Что это такое?
Проектировщик (часто на раннем этапе) создаёт одну большую таблицу, где:
– сотни колонок на все случаи жизни,
– куча
– смешаны данные разных сущностей (например, и клиенты, и заказы, и статусы).
Так проще… пока не начнётся работа с реальными данными.
💥 Что пойдёт не так:
– Производительность падает: индексы не работают эффективно.
– Сложность валидации и бизнес-логики.
– Трудно расширять: каждое изменение — как операция на открытом сердце.
– Нельзя нормально нормализовать: всё связано со всем.
✅ Как избежать:
– Используй нормализацию: выноси повторяющиеся и логически независимые данные в отдельные таблицы.
– Не бойся JOIN-ов — это не зло, а инструмент.
– Планируй схему БД под задачи, а не наоборот.
📌 Пример:
Плохо:
Хорошо:
📎 Вывод: одна таблица ≠ проще. Это короткий путь к хаосу.
Разделяй и властвуй.
Сохрани, чтобы не пришлось рефакторить через полгода 👇
#db
👉 @database_info
Когда бизнес-логика усложняется, а структура БД остаётся в духе Excel — жди беды.
🔴 Что это такое?
Проектировщик (часто на раннем этапе) создаёт одну большую таблицу, где:
– сотни колонок на все случаи жизни,
– куча
NULL
-ов,– смешаны данные разных сущностей (например, и клиенты, и заказы, и статусы).
Так проще… пока не начнётся работа с реальными данными.
💥 Что пойдёт не так:
– Производительность падает: индексы не работают эффективно.
– Сложность валидации и бизнес-логики.
– Трудно расширять: каждое изменение — как операция на открытом сердце.
– Нельзя нормально нормализовать: всё связано со всем.
✅ Как избежать:
– Используй нормализацию: выноси повторяющиеся и логически независимые данные в отдельные таблицы.
– Не бойся JOIN-ов — это не зло, а инструмент.
– Планируй схему БД под задачи, а не наоборот.
📌 Пример:
Плохо:
CREATE TABLE everything (
id INT,
client_name TEXT,
order_price DECIMAL,
order_status TEXT,
delivery_address TEXT,
...
);
Хорошо:
CREATE TABLE clients (
id INT PRIMARY KEY,
name TEXT
);
CREATE TABLE orders (
id INT PRIMARY KEY,
client_id INT REFERENCES clients(id),
price DECIMAL,
status TEXT
);
📎 Вывод: одна таблица ≠ проще. Это короткий путь к хаосу.
Разделяй и властвуй.
Сохрани, чтобы не пришлось рефакторить через полгода 👇
#db
👉 @database_info
👍11
🎯 Мини-гайд: как НЕ спроектировать монстра вместо схемы БД
Когда проект только начинается, есть соблазн «не заморачиваться» и сделать одну большую таблицу на всё.
Спойлер: потом будет больно.
Вот как этого избежать 👇
1. Начинай с нормализации
– Смотри, какие поля повторяются.
– Разделяй по сущностям: клиент ≠ заказ ≠ товар.
– Нормальные формы — не академикам, а тебе на пользу.
2. Определи связи заранее
– Один ко многим? Многие ко многим?
– Используй
3. Не бойся JOIN-ов
– Да, их становится больше.
– Но это лучше, чем сотни
4. Планируй под рост
– Временные костыли становятся постоянными.
– Заложи масштабируемость: разнос сущностей, отдельные таблицы для логов, истории, связей.
5. Назначь ID-шки как бог велел
–
– Не делай
🧠 Помни: хорошо спроектированная схема ускоряет разработку, а не тормозит её.
А переделывать схему сложнее, чем сделать нормально с самого начала.
💬 Как ты подходишь к проектированию схемы?
#db
👉 @database_info
Когда проект только начинается, есть соблазн «не заморачиваться» и сделать одну большую таблицу на всё.
Спойлер: потом будет больно.
Вот как этого избежать 👇
1. Начинай с нормализации
– Смотри, какие поля повторяются.
– Разделяй по сущностям: клиент ≠ заказ ≠ товар.
– Нормальные формы — не академикам, а тебе на пользу.
2. Определи связи заранее
– Один ко многим? Многие ко многим?
– Используй
FOREIGN KEY
, чтобы база помогала тебе, а не мешала.3. Не бойся JOIN-ов
– Да, их становится больше.
– Но это лучше, чем сотни
NULL
- ов и "status_1", "status_2" в одной колонке.4. Планируй под рост
– Временные костыли становятся постоянными.
– Заложи масштабируемость: разнос сущностей, отдельные таблицы для логов, истории, связей.
5. Назначь ID-шки как бог велел
–
PRIMARY KEY
+ автоинкремент или UUID.– Не делай
email
или name
ключом — это путь в баги.🧠 Помни: хорошо спроектированная схема ускоряет разработку, а не тормозит её.
А переделывать схему сложнее, чем сделать нормально с самого начала.
💬 Как ты подходишь к проектированию схемы?
#db
👉 @database_info
👍8
🔗 Мини-гайд по JOIN-ам в SQL
🔸 INNER JOIN
Что делает: оставляет только совпадающие строки из обеих таблиц.
Когда использовать: когда нужны только те записи, у которых есть соответствие.
🧠 Best practice: это дефолтный выбор. Работает быстрее, т.к. отбрасывает всё "лишнее".
🔸 LEFT JOIN
Что делает: возвращает все строки из левой таблицы и
Когда использовать: когда нужно сохранить всё из первой таблицы, даже если во второй нет данных.
🧠 Часто используется для аналитики: "у каких клиентов не было заказов?"
🔸 RIGHT JOIN
Что делает: наоборот — всё из правой таблицы и
Когда использовать: аналогично
🔸 FULL OUTER JOIN
Что делает: объединяет
Когда использовать: когда важны все данные, даже без соответствий.
🧠 Подходит для reconciliation'а или сверки.
❗ Совет
Фильтры (
Используй
Сохрани, чтобы не забыть. А ты какой JOIN используешь чаще всего?
#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 используешь чаще всего?
#db
👉 @database_info
👍11❤1
🧱 Антипаттерн: Ненормализованная схема в SQL
Когда нужно «быстро запилить фичу», руки тянутся сделать одну таблицу, где и заказ, и клиент, и товары — всё в куче.
Пример:
😰 Что пойдет не так:
– Дублирование данных — имя клиента повторяется в каждом заказе.
– Нет масштабируемости — максимум 2 продукта? А если будет 3?
– Трудности с запросами — попробуй посчитать топ-5 товаров. Удачи.
– Адские апдейты — изменить email клиента надо во всех заказах.
✅ Как правильно:
1. Нормализуй. Раздели данные на сущности:
2. Используй внешние ключи.
3. Не бойся JOIN'ов — они для этого и придуманы.
Пример нормализованной структуры:
📌 Да, нормализация требует чуть больше времени. Зато потом вы не утонете в хаосе.
Сохрани, чтобы не забыть — и не повторять чужих ошибок.
#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
);
📌 Да, нормализация требует чуть больше времени. Зато потом вы не утонете в хаосе.
Сохрани, чтобы не забыть — и не повторять чужих ошибок.
#db
👉 @database_info
👍13👎2
Мини-гайд: Как ускорить SELECT’ы в PostgreSQL с помощью покрытия индекса (covering index)
Иногда индекс есть, а запрос всё равно тормозит. Почему?
👉 Потому что обычный индекс помогает найти строку, но потом БД всё равно лезет в таблицу, чтобы достать нужные поля. Это называется heap access — и это дорого.
📌 Решение — покрывающий индекс. Это индекс, который содержит все нужные поля прямо в себе. PostgreSQL с версии 11 умеет делать это через
🔧 Пример:
✅ Теперь PostgreSQL может ответить на запрос только по индексу, не трогая таблицу → быстрее.
📈 Особенно заметный профит:
– На больших таблицах
– В OLTP-нагрузках (много коротких запросов)
– Когда важна задержка ответа (например, API)
⚠️ Но не стоит включать весь ряд в индекс — это увеличит размер и замедлит обновления.
Вывод:
Покрывающие индексы — мощный способ ускорить SELECT без изменения запроса. Используй их там, где читаешь часто, а пишешь редко.
Сохрани, пригодится при оптимизации ⚙️
#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 без изменения запроса. Используй их там, где читаешь часто, а пишешь редко.
Сохрани, пригодится при оптимизации ⚙️
#db
👉 @database_info
👍11
💣 NULL — тихий саботаж в твоей БД
На первый взгляд,
📉 Антипаттерн: беспечное обращение с NULL
Примеры:
Ты думаешь, что отбираешь всех взрослых, но
🙈 Проблема:
📉 Итоги: ошибки в JOIN'ах, WHERE-фильтрах, расчетах.
🛡 Как защититься:
✅ Явно учитывай
✅ Используй
✅ Проверяй
✅ Для агрегаций учитывай поведение
Вывод:
Пиши запросы так, как будто
Сохрани, чтобы не ловить грабли 💥
#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
всегда где-то прячется — и он не на твоей стороне.Сохрани, чтобы не ловить грабли 💥
#db
👉 @database_info
👍10
Как упростить хранение логов и работу с данными?
В помощь отделу ИБ, DevOps- и SRE-инженерам, дата-аналитикам и разработчикам Selectel предлагает облако для OpenSearch.
Вы сможете создать готовый к работе кластер OpenSearch за несколько минут. Это поможет быстро найти, визуализировать и проанализировать данные, события или метрики без ограничений в масштабируемости.
Кроме производительного железа, бесперебойной работы и быстрого масштабирования в облаке Selectel для OpenSearch вы получите:
● бесплатные автоматические бекапы,
● возможность использовать диски разной производительности для холодного и горячего хранения
● Dashboard из коробки для аналитики и управления
Создайте кластер в OpenSearch за несколько кликов в Selectel по ссылке: https://slc.tl/yc44k
Реклама. АО «Селектел», ИНН 7810962785, ERID: 2VtzquyU6q2
В помощь отделу ИБ, DevOps- и SRE-инженерам, дата-аналитикам и разработчикам Selectel предлагает облако для OpenSearch.
Вы сможете создать готовый к работе кластер OpenSearch за несколько минут. Это поможет быстро найти, визуализировать и проанализировать данные, события или метрики без ограничений в масштабируемости.
Кроме производительного железа, бесперебойной работы и быстрого масштабирования в облаке Selectel для OpenSearch вы получите:
● бесплатные автоматические бекапы,
● возможность использовать диски разной производительности для холодного и горячего хранения
● Dashboard из коробки для аналитики и управления
Создайте кластер в OpenSearch за несколько кликов в Selectel по ссылке: https://slc.tl/yc44k
Реклама. АО «Селектел», ИНН 7810962785, ERID: 2VtzquyU6q2
Разбор кейса. Компания переехала с MongoDB на PostgreSQL - зачем и что пошло не так.
Стартап хранил всё в MongoDB — быстро, удобно, JSON-документы летят.
Но через год — бизнес растёт, появляются проблемы:
🔸 Запросы тормозят.
Mongo не любит сложные агрегаты с джойнами по коллекциям.
А бизнесу уже нужно:
– аналитика по заказам
– ретеншн-отчёты
– CRM-связи между сущностями
🔸 Дублирование данных.
Документы растут, становятся вложенными, обновлять — боль.
Классическая проблема: “Обновили e-mail юзера — забыли в двух местах”.
🔸 Сложность поддержки.
Без схемы трудно отследить, что где лежит. Новым разработчикам — боль.
🔁 Решение: PostgreSQL
– Явная схема → валидируем данные сразу
– Поддержка JSONB → можно переехать частями
– Сильный SQL → отчёты, джойны, агрегации — на ура
– Надёжность и mature-инструменты для миграций, бэкапов, мониторинга
⚠️ Подводные камни:
– Миграция данных: пришлось писать парсеры и валидаторы
– Пришлось переосмыслить структуру: из “гибкого” хаоса в нормализованную модель
– Команда училась писать SQL и настраивать индексы
✅ Зато теперь:
– Запросы летят
– Данные валидны
– Аналитика возможна
– Рост — без боли
Переход с NoSQL на SQL — это не “откат назад”, это осознанный апгрейд, когда бизнесу нужен контроль, скорость и предсказуемость.
#db
👉 @database_info
Стартап хранил всё в MongoDB — быстро, удобно, JSON-документы летят.
Но через год — бизнес растёт, появляются проблемы:
🔸 Запросы тормозят.
Mongo не любит сложные агрегаты с джойнами по коллекциям.
А бизнесу уже нужно:
– аналитика по заказам
– ретеншн-отчёты
– CRM-связи между сущностями
🔸 Дублирование данных.
Документы растут, становятся вложенными, обновлять — боль.
Классическая проблема: “Обновили e-mail юзера — забыли в двух местах”.
🔸 Сложность поддержки.
Без схемы трудно отследить, что где лежит. Новым разработчикам — боль.
🔁 Решение: PostgreSQL
– Явная схема → валидируем данные сразу
– Поддержка JSONB → можно переехать частями
– Сильный SQL → отчёты, джойны, агрегации — на ура
– Надёжность и mature-инструменты для миграций, бэкапов, мониторинга
⚠️ Подводные камни:
– Миграция данных: пришлось писать парсеры и валидаторы
– Пришлось переосмыслить структуру: из “гибкого” хаоса в нормализованную модель
– Команда училась писать SQL и настраивать индексы
✅ Зато теперь:
– Запросы летят
– Данные валидны
– Аналитика возможна
– Рост — без боли
Переход с NoSQL на SQL — это не “откат назад”, это осознанный апгрейд, когда бизнесу нужен контроль, скорость и предсказуемость.
#db
👉 @database_info
👍14🔥1
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 без шансов.
Какой используешь ты и почему? 👇
#db
👉 @database_info
Один из самых частых вопросов от разработчиков и 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 без шансов.
Какой используешь ты и почему? 👇
#db
👉 @database_info
👍13❤1
Антипаттерн:
Использовать
Почему это плохо:
🔹 Излишняя нагрузка на сеть и СУБД — выбираются все столбцы, включая ненужные.
🔹 Проблемы с индексами — СУБД может не использовать покрывающий индекс.
🔹 Ломается при изменении схемы — добавил столбец → внезапно изменилось поведение приложения.
🔹 Сложнее читать и поддерживать — особенно в JOIN’ах.
✅ Как правильно:
Запрашивай только нужные поля:
📌 И даже в админках/аналитике лучше явно указывать поля — это дисциплинирует.
Хочешь писать код, который легко масштабировать и отлаживать — забудь про
Сохрани, чтобы не забыть 💾
Поделись с коллегами, которые всё ещё "звёздят" в SQL ✨
#db
👉 @database_info
SELECT *
— удобно, но опасноИспользовать
SELECT *
— значит звать всех на вечеринку, даже если звал только двоих.Почему это плохо:
🔹 Излишняя нагрузка на сеть и СУБД — выбираются все столбцы, включая ненужные.
🔹 Проблемы с индексами — СУБД может не использовать покрывающий индекс.
🔹 Ломается при изменении схемы — добавил столбец → внезапно изменилось поведение приложения.
🔹 Сложнее читать и поддерживать — особенно в JOIN’ах.
✅ Как правильно:
Запрашивай только нужные поля:
SELECT id, name, created_at FROM users;
📌 И даже в админках/аналитике лучше явно указывать поля — это дисциплинирует.
Хочешь писать код, который легко масштабировать и отлаживать — забудь про
SELECT *
.Сохрани, чтобы не забыть 💾
Поделись с коллегами, которые всё ещё "звёздят" в SQL ✨
#db
👉 @database_info
👍12❤1💘1
📕 Борьба с блокировками в PostgreSQL и MS SQL Server для администраторов баз данных, Data engineers, Backend и FullStack-разработчиков.
Как вести работу c PostgreSQL и MS SQL Server без конфликтов и дедлоков.
📗 На вебинаре 20 мая в 20:00 мск разберём:
1. Всё о различных типах блокировок и их механизмах, сходвстах и различиях;
2. Методы предотвращения и разрешения дедлоков;
📘 В результате на практике освоите написание SQL-кода, минимизирующего риски блокировок и дедлоков.
👉 Регистрация и подробности о курсе Базы данных: https://vk.cc/cM56It
Все участники открытого урока получат скидку на курс "Базы данных"
Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576
Как вести работу c PostgreSQL и MS SQL Server без конфликтов и дедлоков.
📗 На вебинаре 20 мая в 20:00 мск разберём:
1. Всё о различных типах блокировок и их механизмах, сходвстах и различиях;
2. Методы предотвращения и разрешения дедлоков;
📘 В результате на практике освоите написание SQL-кода, минимизирующего риски блокировок и дедлоков.
👉 Регистрация и подробности о курсе Базы данных: https://vk.cc/cM56It
Все участники открытого урока получат скидку на курс "Базы данных"
Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576
🔧 Mini-гайд: ускоряем JOIN-ы в больших таблицах
JOIN-ы — мощный инструмент SQL, но на больших объёмах данных могут стать узким горлышком. Вот 5 проверенных способов ускорить их:
1. Индексы по ключам соединения
Без индекса — каждый JOIN превращается в полный перебор.
➤ Пример:
2. Ограничь объём данных до JOIN-а
Фильтруй и агрегируй данные до объединения.
➤ Вместо:
➤ Лучше:
3. Учитывай тип JOIN-а
4. Следи за типами данных
5. Проверь планы выполнения (EXPLAIN)
Не гадай, а смотри, что реально происходит.
📌 Даже один лишний JOIN может уронить производительность. Внимательность + EXPLAIN = уверенность.
Поделись с коллегами — спасёшь чей-то прод.
#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 = уверенность.
Поделись с коллегами — спасёшь чей-то прод.
#db
👉 @database_info
👍13
❌ Антипаттерн: булевы значения как строки
В таблице
На первый взгляд — ерунда. На практике:
– нет валидации: можно вставить
– медленнее сравнение, чем у
– больше места в хранилище,
– сложно агрегировать и строить аналитику.
🔧 Как надо:
– Экономия места (1 байт против 5 и больше)
– Проверка через
– Простой
– Автоматическая поддержка в ORM и UI-форматах
📌 Даже если тебе нужно больше состояний — используй
💡 Чем проще тип — тем меньше шансов на баг.
Сохрани, если в коде встречал такое — и переделай с чистой совестью.
#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
, а не строку.💡 Чем проще тип — тем меньше шансов на баг.
Сохрани, если в коде встречал такое — и переделай с чистой совестью.
#db
👉 @database_info
👍11
Не знаешь на кого пойти учиться ?💥
🛑 Пройди бесплатные онлайн-курсы
🛑 Узнай о самых востребованных профессиях
🛑 Получи уникальную возможность поступить в «Алабуга Политех» после 9 или 11 класса
ПРОЙДИ КУРС ПРЯМО СЕЙЧАС!
ПРОЙДИ КУРС ПРЯМО СЕЙЧАС!
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3❤2🔥2
Индексы в PostgreSQL: когда и как ставить, чтобы ускорить запросы
🔍 Что такое индекс?
Индекс в PostgreSQL — это структура данных (обычно B-tree), позволяющая быстро находить строки по значению столбца, не сканируя всю таблицу.
⚙️ Пример создания простого B-tree-индекса
✅ Best Practices
1. Выбирай правильный тип
*
*
*
2. Индексируй часто фильтруемые и сортируемые поля
* WHERE, JOIN, ORDER BY.
* Например, для запросов типа
создаём составной индекс:
3. Не злоупотребляй
* Каждый индекс занимает место и замедляет INSERT/UPDATE/DELETE.
* Проанализируй
4. Используй частичные индексы
Если условие фильтрации редко меняется, можно сузить индекс:
5. Поддерживай актуальность
Периодически делай
❌ Антипаттерн: “Индекс на всё”
Создание индекса на каждый столбец:
Проблемы:
* Большой объём хранилища.
* Замедление DML-операций.
* Планы запросов могут пропускать некоторые индексы.
💡 Вывод
Правильно подобранные и настроенные индексы — ключ к быстрой работе базы. Сосредоточься на реально востребованных столбцах, комбинируй, не забывай про обслуживание.
Сохрани этот мини-гайд, чтобы не забыть, и поделись с коллегами: какие индексы стали для тебя открытием?
#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-операций.
* Планы запросов могут пропускать некоторые индексы.
💡 Вывод
Правильно подобранные и настроенные индексы — ключ к быстрой работе базы. Сосредоточься на реально востребованных столбцах, комбинируй, не забывай про обслуживание.
Сохрани этот мини-гайд, чтобы не забыть, и поделись с коллегами: какие индексы стали для тебя открытием?
#db
👉 @database_info
👍12❤1
🔗 Сравнение: Типы 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 у тебя чаще всего возникают вопросы?
#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 у тебя чаще всего возникают вопросы?
#db
👉 @database_info
👍9❤1
Кейс: Тонкости работы с транзакциями в распределённых БД
Многие знают, что ACID — основа транзакций в классических СУБД. Но как только переходишь к распределённым решениям (например, CockroachDB, Yugabyte, Spanner), возникают интересные нюансы.
Проблема:
В распределённой БД транзакции могут “подвисать” из-за сетевых задержек, split-brain, clock skew и частых реконнектов между узлами. Строгая согласованность (strong consistency) может негативно влиять на производительность и отклик.
Типичные сложности:
– Distributed deadlocks (где одна часть транзакции ждёт другую через сеть)
– Аномалии времени (например, при использовании синхронизации через NTP)
– Цена глобального commit (двухфазный коммит медленный, а трифазный сложный)
Best practices:
– Минимизируй объём данных внутри одной транзакции
– Используй idempotent-операции, чтобы безопасно повторять неудачные транзакции
– Если возможно, проектируй систему под eventual consistency и асинхронные паттерны (saga, outbox)
– Следи за timeouts и обрабатывай partial failures (например, через retry с exponential backoff)
Кодовый пример (Saga-паттерн для микросервисов):
Saga разбивает большой бизнес-процесс на независимые шаги с откатом (compensating actions).
Вывод:
В распределённых БД транзакции требуют пересмотра архитектуры. Не полагайся только на “магический” commit — строй систему с учётом ошибок и задержек.
А с какими граблями в распределённых транзакциях сталкивался ты?
#db
👉 @database_info
Многие знают, что ACID — основа транзакций в классических СУБД. Но как только переходишь к распределённым решениям (например, CockroachDB, Yugabyte, Spanner), возникают интересные нюансы.
Проблема:
В распределённой БД транзакции могут “подвисать” из-за сетевых задержек, split-brain, clock skew и частых реконнектов между узлами. Строгая согласованность (strong consistency) может негативно влиять на производительность и отклик.
Типичные сложности:
– Distributed deadlocks (где одна часть транзакции ждёт другую через сеть)
– Аномалии времени (например, при использовании синхронизации через NTP)
– Цена глобального commit (двухфазный коммит медленный, а трифазный сложный)
Best practices:
– Минимизируй объём данных внутри одной транзакции
– Используй idempotent-операции, чтобы безопасно повторять неудачные транзакции
– Если возможно, проектируй систему под eventual consistency и асинхронные паттерны (saga, outbox)
– Следи за timeouts и обрабатывай partial failures (например, через retry с exponential backoff)
Кодовый пример (Saga-паттерн для микросервисов):
# Пример на псевдокоде
try:
step1()
step2()
step3()
except Exception:
compensating_action()
Saga разбивает большой бизнес-процесс на независимые шаги с откатом (compensating actions).
Вывод:
В распределённых БД транзакции требуют пересмотра архитектуры. Не полагайся только на “магический” commit — строй систему с учётом ошибок и задержек.
А с какими граблями в распределённых транзакциях сталкивался ты?
#db
👉 @database_info
👍8❤1