7786
Авторский канал про Базы Данных и SQL Ресурсы, гайды, задачи, шпаргалки. Информация ежедневно пополняется! Автор: @energy_it
PostgreSQL умеет обновлять только реально изменившиеся строки и это может сильно сократить WAL и нагрузку!
Многие приложения делают UPDATE даже тогда, когда данные вообще не изменились.
UPDATE users
SET name = 'Alex'
WHERE id = 1;
name уже равен 'Alex', PostgreSQL всё равно создаст новую версию строки (MVCC), запишет WAL, обновит индексы и увеличит нагрузку на autovacuum.SELECT n_tup_upd
FROM pg_stat_user_tables
WHERE relname = 'users';
UPDATE, можно сравнивать старые и новые значения прямо в WHERE:UPDATE users
SET
name = $1,
email = $2
WHERE id = $3
AND (name, email) IS DISTINCT FROM ($1, $2);
IS DISTINCT FROM безопасно сравнивает даже NULL значения, в отличие от обычного !=:SELECT
NULL = NULL,
NULL IS DISTINCT FROM NULL;
WAL, bloat, количество HOT/non-HOT update и нагрузку на autovacuum без изменения архитектуры.
😎 SQL Cheatsheet — удобная шпаргалка для повседневной работы!
Этот репозиторий хорошо подойдёт тем, кто постоянно работает с базами данных и хочет быстро освежать в памяти нужные SQL-конструкции. Здесь всё подано компактно и по делу: запросы, JOIN’ы, агрегации, подзапросы и др. Особенно удобно использовать для подготовки к собеседованиям.
Оставляю ссылочку: GitHub 📱
PostgreSQL может избежать полной сортировки таблицы при ORDER BY ... LIMIT!
Большинство думает, что ORDER BY всегда сортирует вообще всю таблицу. Но в PostgreSQL для LIMIT есть отдельная оптимизация — Top-N Heap Sort.
SELECT *
FROM orders
ORDER BY created_at DESC
LIMIT 10;
scan.execution plan:Sort Method: top-N heapsort
sort мог бы уйти на диск:SET work_mem = '4MB';
EXPLAIN ANALYZE
SELECT *
FROM events
ORDER BY created_at DESC
LIMIT 50;
work_mem PostgreSQL может избежать полной сортировки всех строк и работать заметно быстрее именно благодаря оптимизации Top-N.CREATE INDEX idx_events_created_at
ON events (created_at DESC);
❤️ SQL DEV — большая база для изучения SQL и PostgreSQL!
Здесь собрано огромное количество материалов по SQL: запросы, JOIN’ы, подзапросы, оконные функции, индексы, оптимизация и работа с PostgreSQL. Репозиторий отлично подходит как для изучения базы, так и для углубления в более сложные темы. Особенно полезно то, что здесь много практических примеров и разборов реальных SQL-конструкций.
Оставляю ссылочку: GitHub 📱
📂 Напоминалка по Data Engineering и аналитической архитектуре!
Например, Data Warehouse хранит уже очищенные и структурированные данные для BI и отчетности, Data Lake позволяет складировать сырые данные любого типа и обрабатывать их по мере необходимости, а Data Mesh распределяет владение данными между бизнес-доменами и превращает данные в полноценные data products.
На картинке — основные отличия: как хранятся данные, кто ими управляет, как происходит обработка и для каких задач лучше подходит каждый подход.
Сохрани, чтобы не потерять!
➡️ SQL Ready | #ресурс
😍 SQL шпаргалка для начинающих — база по работе с бд!
Удобный и понятный справочник, где разобраны основные SQL-запросы и конструкции: SELECT, WHERE, JOIN, INSERT, UPDATE и другие ключевые команды. Всё объясняется простым языком с примерами, чтобы быстро понять логику работы с данными и начать применять это в реальных задачах
📌 Оставляю ссылочку: ermita.one
➡️ SQL Ready | #ресурс
📂 Напоминалка по DB Sharding!
Шардинг помогает масштабировать базу данных, распределяя данные между несколькими серверами. На картинке — основные стратегии партиционирования и шардинга.
Например, key-based sharding использует hash-функцию для равномерного распределения записей, а range-based sharding делит данные по диапазонам значений.
Сохрани, чтобы не потерять!
➡️ SQL Ready | #ресурс
🐱 Awesome Postgres — огромная база всего, что связано с PostgreSQL!
В этом репозитории собраны лучшие инструменты, библиотеки, GUI-клиенты, ORM, статьи, курсы и сервисы для работы с PostgreSQL. По сути — это подборка всего полезного для backend-разработчика и DBA в одном месте. Внутри есть материалы не только по базовой работе с БД, но и по мониторингу, репликации, производительности, миграциям и архитектуре.
Оставляю ссылочку: GitHub 📱
📂 Напоминалка по тому, как работает PostgreSQL!
Например, каждое подключение создаёт отдельный процесс, а любые изменения сначала попадают в WAL, и только потом гарантированно пишутся в данные.
На картинке — базовая архитектура: подключения и backend-процессы, shared memory, background и auxiliary процессы и физическое хранение.
Сохрани, чтобы не потерять!
➡️ SQL Ready | #ресурс
Отклики, после которых зовут на собеседования
Главный фокус команды ии-ассистента Софи:
1. Ребята переписали парсер - теперь собирают вакансии из 110+ источников: Telegram, Хабр, LinkedIn и другие.
2. Параллельно сделали умный мэтчер - Софи теперь показывает не всё подряд, а то, что подходит именно вам
(локация, стек, грейд + обучение на фидбэке юзеров).
На этом строится основа автооткликов - быстрых, точных и стабильных.
Следующий шаг - откалибровать мэтчер до точности 80%+, но это невозможно без реальных пользователей.
Поэтому в ближайшие дни они открывают доступ к бесплатному тестированию.
Мест будет немного, так как фокус на качестве.
➡️Если хочешь попасть - подписывайся на канал, там будет анонс о наборе.
😎 SQL Server Kit — практическая база инструментов и материалов!
Репозиторий представляет собой обширную коллекцию скриптов, статей, рекомендаций и утилит для администрирования и разработки на SQL. Внутри собраны решения для диагностики производительности, оптимизации запросов, мониторинга, резервного копирования, работы с индексами и анализа состояния базы данных. Также представлены ссылки на проверенные источники и лучшие практики работы с СУБД.
Оставляю ссылочку: GitHub 📱
Совет на всю жизнь — начните изучать вайбкодинг.
Нейронки уже собирают проекты от идеи до релиза, пишут код, находят и исправляют баги лучше команды айтишников. Это сэкономит вам десятки часов работы.
А чтобы научиться вайбкодить и не совершать ошибки - читайте канал AI-архитектор, где есть:
➖Инструкции по Antigravity и n8n.
➖Связки, которые приносят от 100 000 ₽ за проект
➖Реальный опыт программиста и вайбкодера, который настраивает автоматизацию ИИ для гос. компаний.
Подписывайтесь и смотрите в закрепе, как за 2 дня собрать ИИ-автоматизацию без единой строчки кода: /channel/+eBc7ivvcY34xZTli
Использование data-modifying CTE для цепочек операций в одном запросе!
Обычно изменения и чтение делают разными запросами, что создаёт лишние round-trip и риск рассинхронизации данных между операциями:
UPDATE orders
SET status = 'processing'
WHERE id = 123
RETURNING *;
RETURNING уже даёт доступ к изменённым строкам, но data-modifying CTE позволяет пойти дальше и использовать их в следующих шагах:WITH updated AS (...)
CTE фиксирует результат изменения и гарантирует, что последующие операции работают с тем же набором строк в рамках одного statement:INSERT INTO audit_log (order_id, new_status)
SELECT id, status
FROM updated;
SELECT.data-modifying CTE — это способ строить сложные, но безопасные цепочки операций внутри одного SQL-запроса.
📂 Напоминалка по реляционной модели и SQL!
Например, Primary Key гарантирует уникальность записей, Foreign Key — обеспечивает ссылочную целостность, а JOIN’ы позволяют собирать распределённые данные в единую выборку.
На картинке — основные концепции, которые используются при проектировании и работе с БД.
Сохрани, чтобы не потерять!
➡️ SQL Ready | #ресурс
🖥 Напоминалка по продвинутым функциям работы с датами!Эта шпаргалка собрала ключевые методы, которые позволяют не просто сравнивать даты, а точно извлекать нужные части, округлять по нужному уровню, форматировать для отчётов и рассчитывать интервалы в удобной форме.
➡️ SQL Ready | #шпора
🎓 PostgreSQL должен быть спроектирован до первого инцидента.
В enterprise-среде PostgreSQL — это уже не просто база данных, а часть критичной инфраструктуры с требованиями к доступности, восстановлению, безопасности и мониторингу.
На курсе «Архитектура PostgreSQL для корпоративных систем» разбираем, как строить устойчивую PostgreSQL-инфраструктуру под реальные корпоративные нагрузки.
📌 В фокусе курса:
• High Availability (высокая доступность)
• Disaster Recovery (аварийное восстановление)
• failover-сценарии
• RPO/RTO
• резервирование и мониторинг
• архитектурные ошибки и точки отказа
🐾 АИСыч напоминает: б бы «Backup — это не стратегия. Стратегия — это проверенное восстановление».
SQLREADY20
Почему индекс может не использоваться, даже если он есть!
Очень частая ситуация: индекс создан, запрос написан вроде нормально, но SQL всё равно делает Seq Scan или Full Table Scan.
Имеем такую таблицу:
users(
id,
email,
created_at
)
CREATE INDEX idx_users_email
ON users(email);
SELECT *
FROM users
WHERE email = 'test@example.com';
SELECT *
FROM users
WHERE LOWER(email) = 'test@example.com';
email. А в условии используется выражение:LOWER(email)
LOWER() к строкам; сравнивать результат; читать гораздо больше данных, чем ожидалось.expression/functional index:CREATE INDEX idx_users_email_lower
ON users(LOWER(email));
SELECT *
FROM orders
WHERE DATE(created_at) = '2025-01-10';
DATE(created_at)
created_at может не помочь, потому что функция применяется к колонке.SELECT *
FROM orders
WHERE created_at >= '2025-01-10'
AND created_at < '2025-01-11';
WHERE user_id::text = '100'
user_id — integer, то здесь преобразование применяется к колонке. В такой ситуации обычный индекс по user_id может не использоваться.WHERE user_id = 100
WHERE user_id = '100'
LIKE:WHERE email LIKE '%gmail.com'
100–1000 строк, то Full Scan может быть дешевле, чем прыжки по индексу.LIKE, OR-условия и устаревшая статистика могут сделать индекс бесполезным или менее выгодным для оптимизатора.
📂 Напоминалка по оптимизации баз данных!
Например, индексы ускоряют поиск данных, а репликация помогает распределять нагрузку и повышать отказоустойчивость.
На картинке — 9 основных подходов для улучшения производительности базы данных, которые полезно держать под рукой.
Сохрани, чтобы не потерять!
➡️ SQL Ready | #ресурс
Почему NOT IN может вернуть пустой результат из-за NULL!
Одна из самых неприятных ловушек SQL — поведение NOT IN при наличии NULL. Запрос выглядит абсолютно корректно, но внезапно перестаёт возвращать строки.
Таблицы:
users(id)
bans(user_id)
bans. Часто пишут так:SELECT *
FROM users
WHERE id NOT IN (
SELECT user_id
FROM bans
);
bans.user_id нет NULL — всё работает нормально. Но представим данные:bans
-------
1
2
NULL
0 rows
id <> 1
AND id <> 2
AND id <> NULL
id <> NULL
WHERE проходят только TRUE. Из-за этого всё условие целиком перестаёт выполняться.NULL = 1
NULL <> 1
NULL = NULL
NOT IN с NULL внутри подзапроса становится опасным.NOT EXISTS:SELECT *
FROM users u
WHERE NOT EXISTS (
SELECT 1
FROM bans b
WHERE b.user_id = u.id
);
EXISTS работает нормально: сравнение идёт построчно; NULL не ломает всю проверку; оптимизатор обычно хорошо превращает это в anti-join.SELECT *
FROM users
WHERE id NOT IN (
SELECT user_id
FROM bans
WHERE user_id IS NOT NULL
);
NOT EXISTS обычно считается более безопасным и читаемым решением.NOT IN () и NOT EXISTS могут давать разные планы выполнения в зависимости от СУБД. Но логически для nullable данных: NOT EXISTS почти всегда предпочтительнее.SELECT COUNT(*)
FROM bans
WHERE user_id IS NULL;
NOT IN уже потенциально опасен.NOT IN и NULL плохо сочетаются. Если в подзапросе появляется хотя бы один NULL, условие может перестать возвращать строки вообще. Для таких проверок надёжнее использовать NOT EXISTS.
BUFFERS: как увидеть цену запроса?
Обычный EXPLAIN ANALYZE показывает время выполнения, но почти ничего не говорит о том, сколько данных было прочитано с диска и из памяти.
EXPLAIN (ANALYZE, BUFFERS)
SELECT ...
BUFFERS добавляет статистику по страницам памяти:shared hit — страницы найдены в PostgreSQL shared buffers.shared read — страницы пришлось загрузить в shared buffers; это может быть физический диск или OS page cache.Buffers: shared hit=15000 read=2
Buffers: shared hit=10 read=15000
execution time могут иметь абсолютно разную нагрузку на систему.
Генерация пропущенных дат в отчётах: почему LEFT JOIN не помогает!
Классическая задача — построить отчёт по дням. Например, количество заказов по датам. И внезапно оказывается, что в выдаче нет некоторых дней.
Таблица:
orders(id, created_at)
SELECT
DATE(created_at) AS day,
COUNT(*) AS orders_count
FROM orders
GROUP BY DATE(created_at)
ORDER BY day;
LEFT JOIN сама по себе не помогает — без таблицы дат нечего достраивать. Правильный подход — сначала явно сгенерировать календарь, а потом присоединить данные.generate_series:WITH calendar AS (
SELECT generate_series(
DATE '2026-01-01',
DATE '2026-01-10',
INTERVAL '1 day'
)::date AS day
)
SELECT
c.day,
COUNT(o.id) AS orders_count
FROM calendar c
LEFT JOIN orders o
ON DATE(o.created_at) = c.day
GROUP BY c.day
ORDER BY c.day;
COUNT(o.id) вернёт 0.COUNT(o.id), а не COUNT(*): COUNT(*) посчитает строку календаря даже без совпадений — всегда ≥ 1; COUNT(o.id) считает только реальные заказы — корректный 0 при отсутствии данных.JOIN: ON DATE(o.created_at) = c.day. Так писать удобно, но это ломает использование индекса по created_at.ON o.created_at >= c.day
AND o.created_at < c.day + INTERVAL '1 day'
SELECT
c.day,
COUNT(o.id) AS orders_count,
SUM(COUNT(o.id)) OVER (ORDER BY c.day) AS running_total
FROM calendar c
LEFT JOIN orders o
ON o.created_at >= c.day
AND o.created_at < c.day + INTERVAL '1 day'
GROUP BY c.day
ORDER BY c.day;
WITH bounds AS (
SELECT
MIN(created_at)::date AS min_day,
MAX(created_at)::date AS max_day
FROM orders
),
calendar AS (
SELECT generate_series(min_day, max_day, INTERVAL '1 day')::date AS day
FROM bounds
)
SELECT ...
created_at — timestamptz, границы дня зависят от timezone.
LAG() в SQL — сравниваем строку с предыдущей без JOIN!
Оконная функция LAG() позволяет получить значение из предыдущей строки внутри группы. Это один из самых полезных инструментов для аналитики, логов и временных рядов.
Таблица:
payments(id, user_id, amount, created_at)
Посмотрим предыдущий платёж каждого пользователя:
SELECT
user_id,
amount,
LAG(amount) OVER (
PARTITION BY user_id
ORDER BY created_at
) AS prev_amount
FROM payments;
LAG() сдвигает значение на одну строку назад внутри окна пользователя.SELECT
user_id,
amount,
amount - LAG(amount) OVER (
PARTITION BY user_id
ORDER BY created_at
) AS diff
FROM payments;
SELECT *
FROM (
SELECT
user_id,
status,
LAG(status) OVER (
PARTITION BY user_id
ORDER BY created_at
) AS prev_status
FROM user_logs
) t
WHERE status <> prev_status;
LAG() часто используют для анализа трендов, поиска изменений, расчёта дельт и работы с временными рядами.
Исключающие ограничения: гарантия отсутствия пересечений на уровне БД!
Проверять пересекаются ли интервалы через SELECT перед INSERT — классическая ошибка, которая ломается при конкурентных транзакциях.
SELECT 1
FROM bookings
WHERE room_id = 101
AND start_at < $end
AND end_at > $start;
CREATE EXTENSION IF NOT EXISTS btree_gist;
ALTER TABLE bookings
ADD CONSTRAINT no_overlap
EXCLUDE USING gist (
room_id WITH =,
tsrange(start_at, end_at) WITH &&
);
exclusion constraint — это способ переложить сложную логику (пересечения, диапазоны, уникальность по условиям) с приложения на уровень СУБД с полной защитой от состояния гонки.
Диапазоны как тип данных: убираем двойные условия и баги!
Когда работаешь с интервалами, обычно пишут два условия, и почти всегда где-то ошибаются с границами:
WHERE created_at <= now()
AND shipped_at > now()
tstzrange(created_at, shipped_at)
@> now()
@> проверяет содержит ли диапазон значение, заменяя сразу два условия.created_at <= x AND shipped_at > x:CREATE INDEX ON orders USING GIST (tstzrange(created_at, shipped_at));
GiST-индексом такие запросы работают эффективно даже на больших объёмах.range-типы — это способ убрать класс ошибок с датами и упростить сложную логику.
😍 SQL PostgreSQL Course — информативный курс по SQL с практикой!
Это структурированное обучение по PostgreSQL: от базовых запросов до JOIN’ов, подзапросов и проектирования базы данных. Материал выстроен последовательно, поэтому легко идти шаг за шагом и не теряться в теме. Здесь есть практика с заданиями и ответами, за счёт чего обучение закрепляется.
Оставляю ссылочку: GitHub 📱
Дубликаты после JOIN — откуда берутся и как контролировать!
Одна из частых проблем — внезапное размножение строк после JOIN. Это базовое поведение, если не учтена кардинальность связей.
Таблицы:
orders(id, customer_id, amount)
payments(id, order_id, status)
SELECT
o.id,
o.amount,
p.status
FROM orders o
LEFT JOIN payments p
ON p.order_id = o.id;
orders — payments. То есть один заказ повторится столько раз, сколько у него записей в payments.SELECT
COUNT(*) AS total_orders
FROM orders o
LEFT JOIN payments p
ON p.order_id = o.id;
COUNT(*) считает строки уже после JOIN, а не заказы. Если у заказа 3 платежа — он попадёт в счёт 3 раза. Это одна из самых частых причин кривых метрик.SELECT
COUNT(DISTINCT o.id) AS total_orders
FROM orders o
LEFT JOIN payments p
ON p.order_id = o.id;
DISTINCT — это дополнительная операция, и на больших объёмах она может стоить дорого.payments, JOIN здесь вообще лишний. Лучше контролировать кардинальность до JOINEXISTS:SELECT
o.id,
o.amount
FROM orders o
WHERE EXISTS (
SELECT 1
FROM payments p
WHERE p.order_id = o.id
AND p.status = 'success'
);
EXISTS работает как semi-join: он проверяет факт наличия строки, но не тянет её в результат. За счёт этого одна строка заказа остаётся одной строкой.JOIN всё-таки нужен — агрегируем заранее:SELECT
o.id,
o.amount,
COALESCE(p.has_success, 0) AS has_success
FROM orders o
LEFT JOIN (
SELECT
order_id,
MAX(CASE WHEN status = 'success' THEN 1 ELSE 0 END) AS has_success
FROM payments
GROUP BY order_id
) p ON p.order_id = o.id;
payments к одной строке на order_id, и только потом делаем JOIN. После этого результат становится понятным: одна строка на заказ, без раздувания.GROUP BY o.id, o.amount, p.status
GROUP BY просто фиксирует текущую детализацию. Если у заказа было несколько статусов — строки никуда не денутся.JOIN не создаёт дубликаты сам по себе. Он возвращает строки в соответствии с числом совпадений по условию ON. Если после JOIN строк стало больше — значит реальная связь между таблицами не 1:1, а 1:N или даже N:M.
☕️ Полезную статью нашёл на Хабре: «Ваш RAG не умеет думать. А мой умеет»!
В этой статье:• Разбирается, почему классические RAG-системы на базе векторных БД часто ограничиваются поверхностным поиском;
• Показан подход HippoRAG 2, где память и связи между фактами организованы ближе к графовой модели;
• Объясняется, как эволюционирует работа с данными;
• Рассматривается, как это влияет на SQL/NoSQL слой, архитектуру хранения и построение более осмысленных запросов к данным.
🔊 Продолжайте читать на Habr!
Проверяем дубликаты и считаем уникальные значения!
В больших таблицах важно быстро находить повторяющиеся записи и понимать, сколько уникальных элементов. Это полезно для контроля качества данных и аналитики.
Создадим таблицу пользователей:
CREATE TABLE users (
user_id INT,
email VARCHAR(100)
);
INSERT INTO users VALUES
(1, 'alice@mail.com'),
(2, 'bob@mail.com'),
(3, 'alice@mail.com'),
(4, 'carol@mail.com'),
(5, 'bob@mail.com');
SELECT email, COUNT(*) AS cnt,
CASE WHEN COUNT(*)>1 THEN 'Duplicate' ELSE 'Unique' END AS status
FROM users
GROUP BY email;
COUNT() + GROUP BY группирует одинаковые значения, а CASE сразу классифицирует их как дубликаты или уникальные.email | cnt | status
-----------------------------
alice@mail.com | 2 | Duplicate
bob@mail.com | 2 | Duplicate
carol@mail.com | 1 | Unique
❤️ Нашел вам html5css — простой и наглядный справочник по SQL на русском!
Если хочется быстро разобраться в командах — этот сайт отлично подойдёт. Конструкции объяснены на примерах, с чётким и кратким синтаксисом. Удобно использовать как справочник или экспресс‑повторение.
📌 Оставляю ссылочку: html5css.ru
➡️ SQL Ready | #ресурс
Совет на 2026 год — переходите в ML.
Пока обычные разрабы конкурируют с ИИ-копилотами, ML-инженеры эти самые нейронки создают.
В эпоху нейростей это самые востребованые люди в мире программирования. Зарплаты мидлов начинаются от 250 000 ₽, а у сеньоров в BigTech доходят до 700 000 ₽.
А чтобы освоить его всего за 4 месяца без лишней суеты — изучите канал Артема Алехина.
Его бэкграунд: Руководитель команды в Сбере, валютная удаленка. К 22 годам вышел на доход 1 000 000+ ₽ в месяц.
На канале вы найдёте:
— Всё про самые востребованные стеки(Python, ИИ-агенты, NLP) и почему математика — это не страшно, если учить только нужное.
— Как оформить резюме, чтобы оно пролетало через любые LLM-фильтры и ATS-системы прямо к тимлидам.
— Скрипты переговоров, которые помогли его ученикам прыгнуть с 0 до 360к всего за 8 месяцев.
Во времена острой нехватки ML-разработчиков, это лучшее время, чтобы перекатиться. Переходи и изучай: /channel/+qG_ihzUEkHJlOWVi