Индексы в 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
👍9
🔗 Сравнение: Типы 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
👍10❤2
Кейс: Тонкости работы с транзакциями в распределённых БД
Многие знают, что 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 — строй систему с учётом ошибок и задержек.
А с какими граблями в распределённых транзакциях сталкивался ты?
📲 Мы в MAX
#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 — строй систему с учётом ошибок и задержек.
А с какими граблями в распределённых транзакциях сталкивался ты?
📲 Мы в MAX
#db
👉 @database_info
👍4
Мини-гайд: Как не превратить индексы в PostgreSQL в ловушку для производительности
Добавил пару-тройку индексов — стало быстрее? Отлично! Но помни: индексы — это не бесплатная магия. Вот что важно учитывать:
1. Индексы ускоряют SELECT, но тормозят INSERT/UPDATE/DELETE.
Каждая модификация данных требует обновления всех связанных индексов. Чем их больше — тем медленнее запись.
2. Следи за “мертвыми” индексами.
Иногда индексы создают “на всякий случай”, а потом не используют. PostgreSQL сам не удаляет неиспользуемые индексы. Проверь через
— если
3. Избегай дублирующих индексов.
Одинаковые или почти одинаковые индексы — трата ресурсов. Держи только то, что реально нужно для твоих запросов.
4. Регулярно делай REINDEX и VACUUM.
Индексы могут фрагментироваться и “раздуваться” из-за удалённых данных. Периодическая чистка — залог стабильной производительности.
Вывод:
Индексы — мощный инструмент, но требующий внимания. Не ленись мониторить их эффективность, иначе можно только навредить.
Сохрани, чтобы не попасть в индекс-ловушку!
📲 Мы в MAX
#db
👉 @database_info
Добавил пару-тройку индексов — стало быстрее? Отлично! Но помни: индексы — это не бесплатная магия. Вот что важно учитывать:
1. Индексы ускоряют SELECT, но тормозят INSERT/UPDATE/DELETE.
Каждая модификация данных требует обновления всех связанных индексов. Чем их больше — тем медленнее запись.
2. Следи за “мертвыми” индексами.
Иногда индексы создают “на всякий случай”, а потом не используют. PostgreSQL сам не удаляет неиспользуемые индексы. Проверь через
SELECT * FROM pg_stat_user_indexes WHERE idx_scan = 0;
— если
idx_scan ноль, пора чистить!3. Избегай дублирующих индексов.
Одинаковые или почти одинаковые индексы — трата ресурсов. Держи только то, что реально нужно для твоих запросов.
4. Регулярно делай REINDEX и VACUUM.
Индексы могут фрагментироваться и “раздуваться” из-за удалённых данных. Периодическая чистка — залог стабильной производительности.
Вывод:
Индексы — мощный инструмент, но требующий внимания. Не ленись мониторить их эффективность, иначе можно только навредить.
Сохрани, чтобы не попасть в индекс-ловушку!
📲 Мы в MAX
#db
👉 @database_info
👍6❤1
Антипаттерн: N+1 запросов и как его избежать
Что такое N+1?
При выборке связанных данных ORM (или вручную) сначала делается 1 запрос за основными записями, а потом N дополнительных - по одной для каждой записи, чтобы получить связанные объекты. Например, получить 10 пользователей и для каждого — список их заказов ⇒ 1 запрос к
Почему плохо?
🔹 Высокая нагрузка на базу: запросы “в тоненькую” вместо одного “тяжелого”.
🔹 Задержки сети: множество раунд-трипов увеличивает время ответа.
🔹 Масштабируемость страдает: при росте N время растёт линейно.
Как победить N+1
1. Eager loading (предварительная загрузка)
Загрузка связей сразу вместе с основными объектами.
✅ Сокращает число запросов до 1.
2. Batch loading (групповые запросы)
Если JOIN приводит к дублированию полей, можно сделать два запроса:
✅ Баланс между сложностью и производительностью.
3. DataLoader / кеширование
В GraphQL и приложениях на Node.js часто используют DataLoader:
🔹 Собирает все ключи за тиковый цикл
🔹 Делает один общий запрос
🔹 Раздаёт результаты обратно
4. Правильное проектирование API
• Предусматривайте, какие связи нужны на фронтенде, и загружайте их сразу.
• Разделяйте endpoints: если нужны только пользователи без заказов - делайте лёгкий запрос.
Best practices & подводные камни
🔹 EXPLAIN ANALYZE для проверки плана: убедитесь, что JOIN-ы и IN (…) не приводят к полному сканированию таблиц.
🔹 Пагинация: всегда ограничивайте выборку через
🔹 Будьте осторожны с joinedload на “много ко многим” - может раздувать размер результата.
Сохрани этот пост, чтобы не забыть, и поделись с коллегами!
А у тебя были случаи, когда N+1 съедал всю производительность? Как борешься?
📲 Мы в MAX
#db
👉 @database_info
Что такое N+1?
При выборке связанных данных ORM (или вручную) сначала делается 1 запрос за основными записями, а потом N дополнительных - по одной для каждой записи, чтобы получить связанные объекты. Например, получить 10 пользователей и для каждого — список их заказов ⇒ 1 запрос к
users + 10 запросов к orders. 🚩
# SQLAlchemy-пример “N+1”:
users = session.query(User).all() # 1 запрос
for u in users:
print(u.orders) # для каждого пользователя — отдельный запрос
Почему плохо?
🔹 Высокая нагрузка на базу: запросы “в тоненькую” вместо одного “тяжелого”.
🔹 Задержки сети: множество раунд-трипов увеличивает время ответа.
🔹 Масштабируемость страдает: при росте N время растёт линейно.
Как победить N+1
1. Eager loading (предварительная загрузка)
Загрузка связей сразу вместе с основными объектами.
# SQLAlchemy, joinedload - делает JOIN и подтягивает данные сразу
from sqlalchemy.orm import joinedload
users = session.query(User).options(joinedload(User.orders)).all()
for u in users:
print(u.orders) # не генерирует дополнительных запросов
✅ Сокращает число запросов до 1.
2. Batch loading (групповые запросы)
Если JOIN приводит к дублированию полей, можно сделать два запроса:
-- 1: получить user_id
SELECT id FROM users WHERE active = true;
-- 2: получить все заказы для этих пользователей
SELECT * FROM orders WHERE user_id IN (...список id...);
✅ Баланс между сложностью и производительностью.
3. DataLoader / кеширование
В GraphQL и приложениях на Node.js часто используют DataLoader:
🔹 Собирает все ключи за тиковый цикл
🔹 Делает один общий запрос
🔹 Раздаёт результаты обратно
4. Правильное проектирование API
• Предусматривайте, какие связи нужны на фронтенде, и загружайте их сразу.
• Разделяйте endpoints: если нужны только пользователи без заказов - делайте лёгкий запрос.
Best practices & подводные камни
🔹 EXPLAIN ANALYZE для проверки плана: убедитесь, что JOIN-ы и IN (…) не приводят к полному сканированию таблиц.
🔹 Пагинация: всегда ограничивайте выборку через
LIMIT/OFFSET или курсоры.🔹 Будьте осторожны с joinedload на “много ко многим” - может раздувать размер результата.
Сохрани этот пост, чтобы не забыть, и поделись с коллегами!
А у тебя были случаи, когда N+1 съедал всю производительность? Как борешься?
📲 Мы в MAX
#db
👉 @database_info
👍7
Мини-гайд по трём ключевым сущностям PostgreSQL: соединения, буфер и WAL
1. Соединения (Connections)
PostgreSQL по умолчанию позволяет одновременно до 100 соединений (
🔹 Проблема: слишком много прямых соединений создают нагрузку на память и CPU.
🔹 Решение: используйте пуллинг через PgBouncer или Pgpool-II.
🔹 Совет: на проде стремитесь держать
2. Буфер (Shared Buffers & Work Mem)
PostgreSQL активно использует память для кэширования страниц и сортировок.
🔹
🔹
🔹 Best practice:
🔹 Установите
🔹 Настройте
3. WAL (Write-Ahead Log)
WAL обеспечивает надёжность и репликацию.
🔹
🔹
🔹 Архивация WAL для резервных копий:
🔹 Рекомендации:
🔹 Увеличьте
🔹 Настройте сжатие WAL (pg_wal) для экономии места.
💡 Сохрани, чтобы не забыть!
А как вы оптимизируете соединения, буфер и WAL в своих проектах?
📲 Мы в MAX
#db
👉 @database_info
1. Соединения (Connections)
PostgreSQL по умолчанию позволяет одновременно до 100 соединений (
max_connections).🔹 Проблема: слишком много прямых соединений создают нагрузку на память и CPU.
🔹 Решение: используйте пуллинг через PgBouncer или Pgpool-II.
[databases]
mydb = host=127.0.0.1 port=5432 dbname=mydb
[pgbouncer]
listen_addr = 0.0.0.0
listen_port = 6432
pool_mode = transaction
max_client_conn = 500
default_pool_size = 20
🔹 Совет: на проде стремитесь держать
max_connections < 200 и масштабируйте через пуллер.2. Буфер (Shared Buffers & Work Mem)
PostgreSQL активно использует память для кэширования страниц и сортировок.
🔹
shared_buffers – основной буфер кэша:
shared_buffers = 4GB # ≈25% от RAM на выделенном сервере
🔹
work_mem – память на сортировку/слияние одного потока:
work_mem = 64MB # для сложных запросов с сортировками и хэш-джоинами
maintenance_work_mem = 512MB # для VACUUM/CREATE INDEX
🔹 Best practice:
🔹 Установите
shared_buffers ≈ 25% RAM.🔹 Настройте
work_mem исходя из числа параллельных операций, не превышайте общий объём памяти.3. WAL (Write-Ahead Log)
WAL обеспечивает надёжность и репликацию.
🔹
wal_level – детальность логирования:
wal_level = replica # для потоковой репликации
🔹
checkpoint_timeout и max_wal_size:
checkpoint_timeout = 10min
max_wal_size = 1GB
🔹 Архивация WAL для резервных копий:
archive_mode = on
archive_command = 'cp %p /mnt/backup/wal/%f'
🔹 Рекомендации:
🔹 Увеличьте
max_wal_size, если у вас большие всплески нагрузки.🔹 Настройте сжатие WAL (pg_wal) для экономии места.
💡 Сохрани, чтобы не забыть!
А как вы оптимизируете соединения, буфер и WAL в своих проектах?
📲 Мы в MAX
#db
👉 @database_info
👍8❤1
🎯 Типы баз данных - кратко и по делу
Выбирая базу данных для проекта, важно понимать их ключевые особенности. Ниже - наглядная классификация:
🔷 Реляционные (Relational)
Классика: таблицы со строгими схемами и связями.
📌 ACID, SQL, целостность данных
📌 Идеальны для: финансов, e-commerce, CRM, ERP, банков и инвентаризации
🔷 Документные (Document)
Гибкие NoSQL-базы на основе JSON-документов
📌 Горизонтальное масштабирование, вложенные структуры
📌 Подходят для: CMS, каталогов, мобильных и веб-приложений
🔷 In-Memory
Хранят данные в оперативной памяти — максимум скорости
📌 Используются как кэш, для сессий, real-time аналитики
📌 Примеры: Redis, Memcached
🔷 Графовые (Graph)
Работают с узлами и связями - мощные запросы по связности
📌 Идеальны для соцсетей, рекомендаций, мошеннических схем
📌 Пример: Neo4j
🔷 Временные (Time-Series)
Оптимизированы под работу с временными метками
📌 Подходят для метрик, IoT, логов, финансовых данных
📌 Примеры: InfluxDB, TimescaleDB
🔷 Пространственные (Spatial)
Работают с геоданными и координатами
📌 Используются в GIS, логистике, экологии, городском планировании
🔷 Колончатые (Columnar)
Хранят данные по колонкам - супер для аналитики
📌 Быстрые агрегации, параллельная обработка
📌 Используются в BI, отчетах, хранилищах данных
📌 Пример: ClickHouse
🔷 Ключ-Значение (Key-Value)
Простые NoSQL-базы - пара ключ-значение
📌 Идеальны для кэшей, предпочтений, сессий
📌 Примеры: Redis, DynamoDB
🔍 Правильный выбор базы - залог производительности и масштабируемости проекта.
📲 Мы в MAX
#db
👉 @database_info
Выбирая базу данных для проекта, важно понимать их ключевые особенности. Ниже - наглядная классификация:
🔷 Реляционные (Relational)
Классика: таблицы со строгими схемами и связями.
📌 ACID, SQL, целостность данных
📌 Идеальны для: финансов, e-commerce, CRM, ERP, банков и инвентаризации
🔷 Документные (Document)
Гибкие NoSQL-базы на основе JSON-документов
📌 Горизонтальное масштабирование, вложенные структуры
📌 Подходят для: CMS, каталогов, мобильных и веб-приложений
🔷 In-Memory
Хранят данные в оперативной памяти — максимум скорости
📌 Используются как кэш, для сессий, real-time аналитики
📌 Примеры: Redis, Memcached
🔷 Графовые (Graph)
Работают с узлами и связями - мощные запросы по связности
📌 Идеальны для соцсетей, рекомендаций, мошеннических схем
📌 Пример: Neo4j
🔷 Временные (Time-Series)
Оптимизированы под работу с временными метками
📌 Подходят для метрик, IoT, логов, финансовых данных
📌 Примеры: InfluxDB, TimescaleDB
🔷 Пространственные (Spatial)
Работают с геоданными и координатами
📌 Используются в GIS, логистике, экологии, городском планировании
🔷 Колончатые (Columnar)
Хранят данные по колонкам - супер для аналитики
📌 Быстрые агрегации, параллельная обработка
📌 Используются в BI, отчетах, хранилищах данных
📌 Пример: ClickHouse
🔷 Ключ-Значение (Key-Value)
Простые NoSQL-базы - пара ключ-значение
📌 Идеальны для кэшей, предпочтений, сессий
📌 Примеры: Redis, DynamoDB
🔍 Правильный выбор базы - залог производительности и масштабируемости проекта.
📲 Мы в MAX
#db
👉 @database_info
👍8🔥3❤1
Мини-гайд: VACUUM в PostgreSQL — когда, зачем и как?
PostgreSQL не удаляет строки сразу при
⠀
💡 VACUUM - инструмент для уборки "мусора" и поддержания БД в форме.
Варианты:
Когда запускать вручную?
– Если
– После больших батчевых удалений/обновлений.
– Перед бэкапом (особенно
⠀
Пример:
Лайфхаки:
Не злоупотребляй
Настрой
Следи за bloating:
👉 VACUUM — не уборка по графику, а гигиена твоей БД. Запустишь вовремя - не будет проблем с производительностью.
Сохрани, чтобы не забыть 💾
📲 Мы в MAX
#db
👉 @database_info
PostgreSQL не удаляет строки сразу при
DELETE или UPDATE. Вместо этого они помечаются как "мертвые", а данные продолжают занимать место. Со временем таблицы раздуваются, индексы тормозят, запросы тянут ресурсы.⠀
💡 VACUUM - инструмент для уборки "мусора" и поддержания БД в форме.
Варианты:
VACUUM — убирает мусор, но не возвращает место ОС.VACUUM FULL — перезаписывает таблицу и реально освобождает диск (но блокирует таблицу!).ANALYZE — обновляет статистику планировщика запросов.VACUUM ANALYZE — два в одном: чистка + статистика.Когда запускать вручную?
– Если
autovacuum не справляется (часто видно по pg_stat_user_tables).– После больших батчевых удалений/обновлений.
– Перед бэкапом (особенно
VACUUM FULL для экономии места).⠀
Пример:
VACUUM VERBOSE my_table;
VACUUM FULL my_table;
Лайфхаки:
Не злоупотребляй
FULL — он тяжёлый.Настрой
autovacuum под нагрузки: autovacuum_vacuum_threshold, autovacuum_vacuum_scale_factor и т.д.Следи за bloating:
pgstattuple и pg_bloat_check.👉 VACUUM — не уборка по графику, а гигиена твоей БД. Запустишь вовремя - не будет проблем с производительностью.
Сохрани, чтобы не забыть 💾
📲 Мы в MAX
#db
👉 @database_info
🔥7👍3
Антипаттерн: значения по умолчанию
Кажется безобидным: "Ну не знаю я сейчас значение — пусть будет
– Джоины начинают возвращать меньше строк, чем ты ожидал.
–
–
–
🧱 В чем корень проблемы?
По умолчанию большинство СУБД позволяют
📌 Как избежать?
1. Всегда указывай
2. Думай, нужен ли
3. Добавляй ограничения (
4. Следи за миграциями — новые поля по умолчанию тоже могут быть
✅ Вывод:
Проектируя схему, подходи к
Сохрани, чтобы не зарываться в
📲 Мы в MAX
#db
👉 @database_info
NULL везде, где можноКажется безобидным: "Ну не знаю я сейчас значение — пусть будет
NULL". Но потом:– Джоины начинают возвращать меньше строк, чем ты ожидал.
–
WHERE column = 'X' не находит ничего, потому что там NULL.–
COUNT(column) искажает статистику.–
IS NULL и COALESCE() плодятся по всему коду.🧱 В чем корень проблемы?
По умолчанию большинство СУБД позволяют
NULL, если явно не указано NOT NULL. Это приводит к схеме, где половина полей может быть «ничем», хотя такого смысла в данных нет.📌 Как избежать?
1. Всегда указывай
NOT NULL, если поле обязательно.2. Думай, нужен ли
NULL вообще. Иногда лучше завести отдельный флаг или значение по умолчанию (например, '' или 0).3. Добавляй ограничения (
CHECK), если значение должно быть в определённом диапазоне.4. Следи за миграциями — новые поля по умолчанию тоже могут быть
NULL.✅ Вывод:
Проектируя схему, подходи к
NULL осознанно. Это не просто "ничего" — это потенциальная боль при запросах и анализе.Сохрани, чтобы не зарываться в
NULL -хаос спустя полгода разработки!📲 Мы в MAX
#db
👉 @database_info
👍7❤1🔥1
Какой тип индекса выбрать в PostgreSQL?
Индексы — мощный инструмент для ускорения запросов, но не все они одинаково полезны. В PostgreSQL есть несколько типов индексов, и вот как не промахнуться с выбором:
🔹 B-tree (по умолчанию)
📌 Лучший выбор для:
✅ Поддерживает сортировку.
💡 Используется в 90% случаев.
🔹 Hash
📌 Только для точного сравнения
🚫 Не поддерживает диапазоны, сортировку,
⚠️ Редко используется, но может быть быстрее B-tree на
🔹 GIN (Generalized Inverted Index)
📌 Для массивов,
💡 Отличен при поиске по вложенным структурам или множеству значений.
🔹 GiST (Generalized Search Tree)
📌 Для геоданных (PostGIS), поиска по диапазонам,
💡 Более универсален, но медленнее в некоторых кейсах, чем GIN.
🔹 BRIN (Block Range Index)
📌 Для огромных таблиц, где данные физически упорядочены.
💡 Занимает очень мало места.
⚠️ Не всегда эффективен — зависит от корреляции данных.
✅ Не кидайтесь ставить индекс "на всякий случай". Подбирай тип под паттерн запроса и тип данных.
📲 Мы в MAX
#db
👉 @database_info
Индексы — мощный инструмент для ускорения запросов, но не все они одинаково полезны. В PostgreSQL есть несколько типов индексов, и вот как не промахнуться с выбором:
🔹 B-tree (по умолчанию)
📌 Лучший выбор для:
=, <, >, BETWEEN, ORDER BY.✅ Поддерживает сортировку.
💡 Используется в 90% случаев.
CREATE INDEX idx_users_name ON users(name);
🔹 Hash
📌 Только для точного сравнения
=.🚫 Не поддерживает диапазоны, сортировку,
LIKE.⚠️ Редко используется, но может быть быстрее B-tree на
=.
CREATE INDEX idx_users_email_hash ON users USING hash(email);
🔹 GIN (Generalized Inverted Index)
📌 Для массивов,
jsonb, full-text search.💡 Отличен при поиске по вложенным структурам или множеству значений.
CREATE INDEX idx_data_tags ON posts USING gin(tags);
🔹 GiST (Generalized Search Tree)
📌 Для геоданных (PostGIS), поиска по диапазонам,
tsvector.💡 Более универсален, но медленнее в некоторых кейсах, чем GIN.
CREATE INDEX idx_events_location ON events USING gist(location);
🔹 BRIN (Block Range Index)
📌 Для огромных таблиц, где данные физически упорядочены.
💡 Занимает очень мало места.
⚠️ Не всегда эффективен — зависит от корреляции данных.
CREATE INDEX idx_logs_timestamp ON logs USING brin(timestamp);
✅ Не кидайтесь ставить индекс "на всякий случай". Подбирай тип под паттерн запроса и тип данных.
📲 Мы в MAX
#db
👉 @database_info
👍11
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
Один из самых частых вопросов:
«Нам вообще 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
👍4❤1🔥1
❌ Антипаттерн: UUID как PK без учёта последствий
Выглядит красиво: глобально уникальный идентификатор, можно генерировать на клиенте, удобно в распределённых системах. Но...
💣 Проблемы:
– Большой размер (16 байт vs 4 байта у INT)
– Плохая локальность: индекс B-Tree фрагментируется
– Медленнее вставки, особенно при высоких нагрузках
– Нагружает сеть, если часто передаёшь PK
📉 В PostgreSQL это особенно заметно: индекс на UUID-ключе может вести себя гораздо хуже, чем на
✅ Как делать правильно:
1. Если всё в одной БД: используй
2. Если нужен UUID:
– генерируй
– либо
– или комбинируй автоинкремент + случайный суффикс
3. Храни UUID как
🧠 UUID — мощный инструмент, но не серебряная пуля. Прежде чем делать его
Сохрани, чтобы не собирать фрагментированные индексы вручную 😅
📲 Мы в MAX
#db
👉 @database_info
Выглядит красиво: глобально уникальный идентификатор, можно генерировать на клиенте, удобно в распределённых системах. Но...
💣 Проблемы:
– Большой размер (16 байт vs 4 байта у INT)
– Плохая локальность: индекс B-Tree фрагментируется
– Медленнее вставки, особенно при высоких нагрузках
– Нагружает сеть, если часто передаёшь PK
📉 В PostgreSQL это особенно заметно: индекс на UUID-ключе может вести себя гораздо хуже, чем на
BIGSERIAL.✅ Как делать правильно:
1. Если всё в одной БД: используй
BIGINT или BIGSERIAL2. Если нужен UUID:
– генерируй
UUID v7 (появился в 2022, содержит компонент времени → лучше упорядочен)– либо
UUID v1 (временной, но с оговорками по безопасности)– или комбинируй автоинкремент + случайный суффикс
3. Храни UUID как
UUID, а не как VARCHAR(36) — это экономит место и CPU🧠 UUID — мощный инструмент, но не серебряная пуля. Прежде чем делать его
PRIMARY KEY, подумай: что ты реально выигрываешь?Сохрани, чтобы не собирать фрагментированные индексы вручную 😅
📲 Мы в MAX
#db
👉 @database_info
👍8🔥2👎1
Почему одна и та же БД летает на staging и тормозит в проде
Знакомо? На staging сервере — отклик 100мс, на проде — секундные таймауты. Хотя база одна и та же, схема такая же. Что не так?
Вот 5 частых причин:
1. Разный объём данных
На staging — 10k строк, на проде — 10 млн. Индексы, которые "и так нормально", внезапно перестают справляться.
2. Отсутствие/различие индексов
DevOps мог не раскатить нужные индексы в прод. Или, наоборот, staging набит экспериментальными индексами.
3. Параметры конфигурации БД
4. Статистика устарела
На проде реже делается
5. Разное поведение приложения
Прод нагружается параллельно десятками потоков. Staging — ты и Postman.
🛠 Что делать:
– Сравни настройки сервера (
– Проверь
– Не доверяй staging — тестируй на продоподобных данных
📲 Мы в MAX
#db
👉 @database_info
Знакомо? На 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
👍6🔥2
Антипаттерн: использование
Кажется безобидным, правда? Особенно на этапе прототипирования. Но как только ваш запрос с
🔻 Почему это плохо:
– Избыточные данные. Вы тянете всё, включая ненужные поля. Это бьёт по сети, памяти и CPU.
– Ломкость кода. Добавили колонку в таблицу — и, внезапно, старый код падает, потому что ожидал другую структуру.
– Плохая читаемость. Непонятно, какие поля реально нужны. Это мешает отладке и сопровождению.
– Невозможно использовать covering index — индекс по нужным колонкам не спасёт, если вы вытаскиваете всё подряд.
📌 Как правильно:
✅ Явно указывайте нужные поля:
✅ Работаете с ORM — настраивайте выборку полей в
✅ В аналитике? Даже при джойнах и CTE — указывайте, что реально используете.
🧠 Запомни: чем меньше данных ты запрашиваешь — тем быстрее и стабильнее работает твой код.
💬 А ты встречал
📲 Мы в MAX
#db
👉 @database_info
SELECT * в продакшенеКажется безобидным, правда? Особенно на этапе прототипирования. Но как только ваш запрос с
SELECT * уходит в прод, начинаются проблемы:🔻 Почему это плохо:
– Избыточные данные. Вы тянете всё, включая ненужные поля. Это бьёт по сети, памяти и CPU.
– Ломкость кода. Добавили колонку в таблицу — и, внезапно, старый код падает, потому что ожидал другую структуру.
– Плохая читаемость. Непонятно, какие поля реально нужны. Это мешает отладке и сопровождению.
– Невозможно использовать covering index — индекс по нужным колонкам не спасёт, если вы вытаскиваете всё подряд.
📌 Как правильно:
✅ Явно указывайте нужные поля:
SELECT id, name, created_at FROM users;
✅ Работаете с ORM — настраивайте выборку полей в
select() или .only() (в зависимости от фреймворка).✅ В аналитике? Даже при джойнах и CTE — указывайте, что реально используете.
🧠 Запомни: чем меньше данных ты запрашиваешь — тем быстрее и стабильнее работает твой код.
💬 А ты встречал
SELECT * в проде? Или, может, сам когда-то писал так?📲 Мы в MAX
#db
👉 @database_info
👍5❤1🔥1
Нужно быстро поднять PostgreSQL для MVP или pet-проекта?
В MWS Cloud Platform база данных PostgreSQL разворачивается за минуты и сразу готова к работе:
Подходит для любого проекта — от интернет-магазина до высоконагруженного backend-сервиса.
🆓 До 31 марта production-ready PostgreSQL в облаке — бесплатно
🔥 Запустите свой проект, протестируйте под нагрузкой и спокойно оставляйте базу в продакшене.
Попробовать бесплатно*
* Скидка 100% на оплату сервиса Managed PostgreSQL предоставляется в период с 9 февраля по 31 марта 2026 года для участников акции. Подробные условия — по ссылке
В MWS Cloud Platform база данных PostgreSQL разворачивается за минуты и сразу готова к работе:
⏺️ готовые конфигурации CPU и RAM под разные типы нагрузок⏺️ high availability или standalone конфигурации, автоматические бэкапы⏺️ гарантированные мощности CPU, консистентный API и удобный cloud-native IAM⏺️ сетевые или сверхбыстрые NVMe-диски под разные сценарии⏺️ постоянный primary endpoint: адрес не меняется при failover или switchover⏺️ до 3 read-only точек подключения — удобно для подключения аналитики⏺️ поддержка популярных расширений PostgreSQL "из коробки"
Подходит для любого проекта — от интернет-магазина до высоконагруженного backend-сервиса.
Попробовать бесплатно*
* Скидка 100% на оплату сервиса Managed PostgreSQL предоставляется в период с 9 февраля по 31 марта 2026 года для участников акции. Подробные условия — по ссылке
Please open Telegram to view this post
VIEW IN TELEGRAM
🔴 Антипаттерн: игнорирование поведения NULL в SQL
Когда ты пишешь
❌ Пример проблемы:
Если
✔️ Как избежать:
1. Явно учитывай NULL'ы:
2. Работай с COALESCE, если допустимо:
📌 То же касается и
📌 Агрегации (
Вывод:
NULL — не "ничего", а "неизвестно", и SQL строго это уважает. Не учитывая это, легко получить баг, который даже не заметишь сразу.
💡 Всегда проверяй поведение WHERE, JOIN и агрегатов с
Сохрани, чтобы не ловить баги на ровном месте.
📲 Мы в MAX
#db
👉 @database_info
Когда ты пишешь
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
👍6🔥1
Как понять, что вашему проекту нужен полнотекстовый поиск, а не
Часто разработчики в PostgreSQL начинают с простого:
Но уже при 10k+ строк и регулярных запросах начинаются тормоза. Значит, пора на следующий уровень — полнотекстовый поиск.
🔍 Когда
– Сложные запросы с несколькими
– Не масштабируется: без индексов → full scan
– Нет нормализации слов:
💡 Решение:
📈 Плюсы:
– Работают GIN-индексы
– Поддержка морфологии и синонимов
– Быстрее и точнее на больших объемах
⚠️ Подводные камни:
– Нужна настройка языкового словаря
–
– Требуется обновление индекса при INSERT/UPDATE
🛠 Как включить GIN-индекс:
👉 Если пользователи ищут по тексту — не тормозите
Сохрани, чтобы потом не мучиться с explain-ами 😉
📲 Мы в MAX
#db
👉 @database_info
ILIKEЧасто разработчики в PostgreSQL начинают с простого:
SELECT * FROM articles WHERE title ILIKE '%postgres%';
Но уже при 10k+ строк и регулярных запросах начинаются тормоза. Значит, пора на следующий уровень — полнотекстовый поиск.
🔍 Когда
ILIKE — плохо:– Сложные запросы с несколькими
ILIKE– Не масштабируется: без индексов → full scan
– Нет нормализации слов:
postgres, PostgreSQL, постгрес — всё разное💡 Решение:
to_tsvector + to_tsquery
SELECT * FROM articles
WHERE to_tsvector('russian', title) @@ to_tsquery('russian', 'postgres');
📈 Плюсы:
– Работают GIN-индексы
– Поддержка морфологии и синонимов
– Быстрее и точнее на больших объемах
⚠️ Подводные камни:
– Нужна настройка языкового словаря
–
tsquery не такая гибкая, как regex– Требуется обновление индекса при INSERT/UPDATE
🛠 Как включить GIN-индекс:
CREATE INDEX idx_articles_title_search
ON articles USING GIN (to_tsvector('russian', title));
👉 Если пользователи ищут по тексту — не тормозите
ILIKE, внедряйте полнотекст!Сохрани, чтобы потом не мучиться с explain-ами 😉
📲 Мы в MAX
#db
👉 @database_info
👍4🤔1🤡1
🧱 Антипаттерн: использование UUID как Primary Key без оглядки
На первый взгляд, UUID — классный способ генерировать уникальные идентификаторы:
– не зависят от последовательности
– удобны для распределённых систем
– безопасны для внешнего экспонирования
Но если ты просто заменишь
❌ В чём подвох:
– Производительность INSERT'ов резко падает: UUID случайные → нет locality → индекс (обычно B-Tree) постоянно фрагментируется
– Индексы пухнут: UUID = 16 байт, BIGINT = 8 байт. Разница кажется небольшой, но на больших объёмах — это боль
– Чтение медленнее: за счёт увеличенного размера индексов и меньшего кэш-хита
✅ Как избежать:
1. Если нет жёсткой необходимости в UUID — не используй их как PK
2. Нужен UUID? Сделай его вторичным индексом, а PK оставь автоинкрементным
3. Или хотя бы используй UUID v7 (новый стандарт с time-based префиксом) — он улучшает локальность по сравнению с v4
Пример:
→ Внутри БД — быстрый
→ Для внешних API — UUID. Удобно и производительно.
📲 Мы в MAX
#db
👉 @database_info
На первый взгляд, 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
👍6
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
Очень важно понимать порядок выполнения.
В 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
🤔5👍2
🚀 Подборка полезных 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 и др.
1C разработка 📌
https://max.ru/odin1c_rus Cтатьи, курсы, советы, шаблоны кода 1С
Программирование C++📌
https://max.ru/cpp_lib Библиотека C/C++ разработчика
Программирование 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 Свежие новости Москвы
Системное администрирование, 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 и др.
1C разработка 📌
https://max.ru/odin1c_rus Cтатьи, курсы, советы, шаблоны кода 1С
Программирование C++📌
https://max.ru/cpp_lib Библиотека C/C++ разработчика
Программирование 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 Свежие новости Москвы
MAX
Системный Администратор | Sysadmin Windows & Linux Server. …
Блог практикующего админа. Настройка Windows Server, Active Directory (AD), GPO и терминальных серверов (RDP). Работа с Linux: Ubuntu, CentOS, Debian. Сетевое …
👎6💩5❤3😐3
Индексы в PostgreSQL: Часть 1 — B-Tree
Если ты создавал индекс в PostgreSQL по умолчанию, значит, это B-Tree.
Но как он работает и когда он реально полезен?
Что это такое?
B-Tree индекс — сбалансированное дерево поиска.
PostgreSQL автоматически использует его для:
=\` (равенство)
> < >= <= (сравнения)
BETWEEN
LIKE 'abc%' (только префикс, без
Пример:
Запрос не будет сканировать всю таблицу — он сразу пойдёт по дереву.
Подводные камни:
1. Не работает для произвольных LIKE:
2. Осторожно с функциями:
3. Многоколонковые индексы:
Порядок важен.
Когда ставить?
- Уникальные поля (email, username).
- Часто используемые фильтры и JOIN-колонки.
- Сортировки (
Вывод:
B-Tree — твой “универсальный солдат”. Но не пихай его на всё подряд. Перед добавлением — смотри
Сохрани, чтобы не забыть!
📲 Мы в MAX
#db
👉 @database_info
Если ты создавал индекс в 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
👍7❤1🔥1