7786
Авторский канал про Базы Данных и SQL Ресурсы, гайды, задачи, шпаргалки. Информация ежедневно пополняется! Автор: @energy_it
📂 Напоминалка по структурам баз данных!
Например, Skiplist ускоряет поиск в памяти, Hash-индекс даёт доступ за O(1), а B-tree и LSM-дерево оптимизируют работу с диском и записью.
На картинке — 8 структур данных, которые стоит держать под рукой, чтобы понимать, как устроены индексы и хранение в БД.
Сохрани, чтобы не забыть!
➡️ SQL Ready | #ресурс
❤️ SQL-EX — интерактивный тренажёр с задачами!
Если хочешь учиться через практику, этот сайт отличный инструмент. Здесь ты пишешь запросы прямо в браузере, получаешь мгновенную обратную связь и видишь результат. Подойдёт для закрепления теории, подготовки к собеседованию или реальных задач в работе с бд.
📌 Оставляю ссылочку: sql-ex.ru
➡️ SQL Ready | #ресурс
❤️ 30-Days-of-SQL — тридцатидневный челлендж в обучении!
Репозиторий предлагает серию упражнений и заданий на каждый день, которые охватывают ключевые темы: выборки, агрегации, подзапросы, оконные функции и др. Формат один день - одна задача помогает не перегружаться и выстраивать структурированный план обучения. Отлично подходит для практики, подготовки к собеседованиям и укрепления знаний.
Оставляю ссылочку: GitHub 📱
📂 Напоминалка по HTTP-стеку для разработки и инфраструктуры!
Например, HTTP/2 ускоряет загрузку за счёт мультиплексирования, а HTTP/3 делает обмен ещё быстрее, используя QUIC поверх UDP — уже стандарт для современных браузеров и CDN.
На картинке — ключевые компоненты HTTP-экосистемы, которые важно держать под рукой.
Сохрани, чтобы не забыть!
➡ SQL Ready | #ресурс
😎 PopSQL Learn — быстрый и структурный старт в SQL!
Если хочешь разобраться с SQL не по документации, а через чёткие объяснения и примеры запросов, этот сайт точно пригодится. Темы здесь идут от базовых до сложных концепций, всё с примерами, которые можно сразу повторить. Удобно, когда нужна практика для проектов или собеседований.
📌 Оставляю ссылочку: popsql.com
➡️ SQL Ready | #ресурс
Партицирование в оконных функциях — когда нужно работать с топами внутри групп!
Оконные функции в SQL — стандартный инструмент аналитики. Один из частых кейсов: найти «лучшие» записи внутри каждой группы, не сворачивая таблицу и не теряя строки.
Представим таблицу:
products(id, category, price)
SELECT *
FROM (
SELECT
*,
ROW_NUMBER() OVER (PARTITION BY category ORDER BY price DESC, id DESC) AS rn
FROM products
) t
WHERE rn = 1;
PARTITION BY формирует независимые окна для каждой категории.ROW_NUMBER() нумерует строки внутри каждой партиции, а не по всей таблице.SELECT id, category, price
FROM (
SELECT
id, category, price,
ROW_NUMBER() OVER (PARTITION BY category ORDER BY price DESC, id DESC) AS rn
FROM products
) t
WHERE rn <= 3
ORDER BY category, price DESC;
PARTITION BY запрос взял бы топ-3 по всей таблице, а не по категориям.GROUP BY, потому что не агрегируют (не схлопывают) строки, а дополняют их аналитическими метками.GROUP BY и JOIN, через коррелированный подзапрос:SELECT *
FROM products
WHERE price = (
SELECT MAX(price)
FROM products p2
WHERE p2.category = products.category
);
ties).PARTITION BY в оконных функциях, когда логика должна применяться внутри каждой группы независимо, а строки нужно сохранить целиком.
📂 Напоминалка про Modem vs Router!
Модем отвечает за подключение к провайдеру и получение публичного IP, а роутер управляет локальной сетью: маршрутизирует трафик, выполняет NAT и раздаёт адреса устройствам.
На картинке — ключевые отличия и базовая схема работы.
Сохрани, чтобы не забыть!
➡️ SQL Ready | #ресурс
❤️ Red Blob Games — полезный сайт для визуального понимания алгоритмов!
Если тебе сложно понять алгоритмы по учебникам — этот ресурс решает проблему. Автор объясняет графы, геометрию, деревья, меши из геймдева через понятные визуализации и интерактивы. Сложные идеи здесь раскладываются на простые шаги.
📌 Оставляю ссылочку: redblobgames.com
➡️ SQL Ready | #ресурс
Генерация фейковых данных для тестов с мгновенной вставкой в любую таблицу!
SQL понимает VALUES как виртуальную таблицу, поэтому можно писать много строк прямо в INSERT:
INSERT INTO users (id, email, name) VALUES
(1, 'alice@mail.com', 'Alice'),
(2, 'bob@mail.com', 'Bob'),
(3, 'carol@mail.com', 'Carol');
CREATE TABLE users (
id int PRIMARY KEY,
email text,
name text
);
Развернуть PostgreSQL в MWS Cloud Platform ⬜️ — быстрее, чем вспомнить пароль от pgAdmin. И точно быстрее, чем объяснить DevOps'у, зачем ещё одна база.
Всего несколько минут и у вас:
⏺️готовая база на сетевых или локальных дисках
⏺️постоянный primary endpoint
⏺️безопасное подключение через Private Link
⏺️автоматические бэкапы и обслуживания по твоему расписанию
☕️ На Хабре вышла подробная статья про автоматизацию развертывания PostgreSQL-кластеров в изолированной инфраструктуре.
В этой статье:• Показан реальный подход к автоматическому развёртыванию PostgreSQL в закрытом контуре;• Разбирается поддержка нескольких ОС, версий СУБД и схем отказоустойчивости;• Описана автоматическая проверка соответствия требованиям архитектуры;• Приведён практический кейс внедрения, рассчитанный на эксплуатацию в крупных корпоративных системах.
🔊 Продолжайте читать на Habr!
Как понять, что PostgreSQL работает на устаревшей статистике?
PostgreSQL хранит информацию о последнем сборе статистики:
SELECT relname,
last_analyze,
last_autoanalyze,
n_live_tup
FROM pg_stat_user_tables;
last_analyze — когда статистика обновлялась вручную,last_autoanalyze — когда это делал autovacuum.SELECT relname,
n_live_tup,
last_analyze,
last_autoanalyze
FROM pg_stat_user_tables
ORDER BY n_live_tup DESC;
last_analyze — оптимизатор работает вслепую.ANALYZE;
ANALYZE orders;
🖥 Ищем клиентов без единого заказа — полезный приём для выявления неактивных пользователей и повышения конверсии!
Цель — найти всех зарегистрированных пользователей, которые так и не оформили ни одного заказа. Это поможет вернуться к ним с акциями или напоминаниями.
Основные моменты:
• LEFT JOIN — соединяем таблицы, чтобы сохранить всех клиентов, даже тех, у кого нет заказов.
• WHERE o,id IS NULL — отбираем только тех, для кого заказов не найдено.
• SELECT — выводим имя, email и дату регистрации.
Условный UPSERT: как не обновлять строки без изменений?
Обычный UPSERT обновляет строку всегда, даже если данные не изменились — это лишние блокировки, WAL и autovacuum.
PostgreSQL позволяет сделать условный UPDATE прямо в ON CONFLICT:
ON CONFLICT (id) DO UPDATE
...
WHERE users.email IS DISTINCT FROM EXCLUDED.email
OR users.name IS DISTINCT FROM EXCLUDED.name;
UPDATE не выполняется вообще.EXCLUDED — это “новая” версия строки, users.* — текущая версия в таблице.users.col IS DISTINCT FROM EXCLUDED.col
NULL и не попадает в ловушки трёхзначной логики.
FILTER в агрегатных функциях PostgreSQL!
В аналитических запросах часто нужно посчитать несколько показателей из одной таблицы. В PostgreSQL для этого есть FILTER, позволяющий задавать условия отдельно для каждой агрегатной функции, не влияя на весь запрос.
Представим таблицу заказов:
orders(id, customer_id, amount, status)
SELECT
COUNT(*) AS total_orders,
COUNT(*) FILTER (WHERE status = 'completed') AS completed_orders
FROM orders;
FILTER применяется непосредственно к агрегатной функции и ограничивает только те строки, которые участвуют в её расчёте.SELECT
COUNT(*) AS total_orders,
COUNT(*) FILTER (WHERE status = 'completed') AS completed_orders,
COUNT(*) FILTER (WHERE status = 'canceled') AS canceled_orders,
SUM(amount) FILTER (WHERE status = 'completed') AS completed_amount
FROM orders;
FILTER можно использовать с любыми агрегатами:AVG(amount) FILTER (WHERE status = 'completed')
MAX(amount) FILTER (WHERE status = 'completed')
MIN(amount) FILTER (WHERE status = 'completed')
FILTER работает только с агрегатными функциями и применяется внутри SELECT, дополняя, а не заменяя WHERE и GROUP BY.
Сравнение наборов и вычисление пересечения по ключу!
Нужно быстро получить пересечение двух таблиц по ключу? Используйте JOIN по колонке, которая логически должна совпадать в обоих наборах:
JOIN table_b b ON a.id = b.id
SELECT a.id
CREATE TABLE table_a(id int);
CREATE TABLE table_b(id int);
INSERT INTO table_a VALUES (1),(2),(3);
INSERT INTO table_b VALUES (2),(3),(4);
JOIN, вы увидите только 2,3 как пересечение наборов.
Find + Update в одном проходе!
Найдём строки с невозможными значениями и сразу подготовим их к UPDATE:
WITH c AS (SELECT id FROM products WHERE price < 0 LIMIT 3)
CTE c вернёт проблемные id.UPDATE products SET price = 0
CTE, чтобы не рассинхронизировать find/update:WHERE id IN (SELECT id FROM c);
CREATE TABLE products(id int PRIMARY KEY, price int);
INSERT INTO products VALUES (1,-10),(2,-5),(3,100);
find+update снова и убедитесь, что исправление точечное и атомарное.
Транзакция, которая берёт только свободные строки!
В конкурентной обработке задач важно не брать строку, уже заблокированную другой транзакцией, и не ждать её освобождения.
PostgreSQL делает это через:
FOR UPDATE SKIP LOCKED
BEGIN;
SELECT id FROM jobs WHERE status='queued' FOR UPDATE;
BEGIN;
SELECT id FROM jobs WHERE status='queued' FOR UPDATE SKIP LOCKED LIMIT 1;
SKIP LOCKED. Нет двойной обработки, ожиданий и внешних зависимостей.
Транзакции в SQL — почему частичные изменения хуже ошибки!
Работа с несколькими связанными таблицами в одном сценарии должна быть атомарной. Без TRANSACTION при автокоммите каждый UPDATE фиксируется отдельно — и есть риск получить несогласованное состояние.
Таблицы:
wallet(user_id, balance)
payments(id, user_id, amount, status)
done.UPDATE wallet SET balance = balance - 100 WHERE user_id = 7;
-- сбой соединения тут
UPDATE payments SET status = 'done' WHERE id = 55;
BEGIN;
UPDATE wallet SET balance = balance - 100 WHERE user_id = 7;
UPDATE payments SET status = 'done' WHERE id = 55;
COMMIT;
COMMIT изменения видны только в текущей сессии и не становятся устойчивыми. Если все шаги успешны — фиксируется сразу всё.BEGIN;
UPDATE wallet SET balance = balance - 100 WHERE user_id = 7;
UPDATE payments SET status = 'done' WHERE id = 55;
ROLLBACK;
ROLLBACK происходит именно при разрыве соединения или явном откате.UPDATE wallet
SET balance = balance - 100
WHERE user_id = 7 AND balance >= 100;
UPDATE payments
SET status = 'done'
WHERE id = 55 AND status = 'pending';
UPDATE выполняем в одной транзакции, затем проверяем rowcount: если любой запрос затронул 0 строк — ROLLBACK и обработка как ошибка.SELECT ... FOR UPDATE также работает только в той же транзакции, где будет обновление. Любая операция списания + фиксации платежа = транзакция.
UPDATE без холостых перезаписей!
Обычный UPDATE может перезаписывать строку, даже если значение не изменилось.IS DISTINCT FROM сравнивает значения NULL-безопасно и без UNKNOWN:
AND u.name IS DISTINCT FROM 'Alice';
name уже Alice — условие ложно, и строка не обновляется вообще.AND u.email IS DISTINCT FROM EXCLUDED.email;
CREATE TABLE users(id int PRIMARY KEY, name text);
INSERT INTO users VALUES (1, 'Bob');
UPDATE сверху, второй раз таблица не изменится и ничего не запишет.UPDATE должен менять только то, что отличается и SQL уже даёт для этого инструменты.
Всех с наступающим 2026 годом! 🎄
Поставлю себе цель: набрать более 20 тысяч подписчиков ✍️
Знали, что NOT IN — главный источник тихих багов, если в подзапросе есть NULL?
Этот запрос выглядит логично, но опасен:
WHERE user_id NOT IN (SELECT id FROM users);
NULL, условие станет UNKNOWN, и не вернётся ни одной строки.WHERE NOT EXISTS (SELECT 1 FROM users u WHERE u.id = orders.user_id);
NULL, не ломает логику и читается однозначно.CREATE TABLE users(id int);
INSERT INTO users VALUES (1), (2), (NULL);
SELECT 1 AS test WHERE 3 NOT IN (SELECT id FROM users);
NOT EXISTS, логика вернётся в норму.
🖥 PostgreSQL: работа с массивами!В этой шпаргалке собраны ключевые функции и операторы PostgreSQL для создания, трансформации, агрегации и фильтрации массивов, а также проверки их пересечения и вхождения элементов. Материал охватывает приведение типов, разворачивание массивов в строки, сбор данных в массивы и использование операторов для логических проверок.
➡️ SQL Ready | #шпора
Оконные функции ROW_NUMBER() в SQL — нумерация строк для аналитики!ROW_NUMBER() присваивает уникальный порядковый номер строкам внутри логического окна. Данные не объединяются в группы, строки остаются как есть — это ключевое отличие от GROUP BY.
Таблица:
payments(id, user_id, amount, created_at)
user_id, а нумерация идёт по дате от старых к новым:SELECT id, user_id, amount,
ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY created_at ASC) AS rn
FROM payments;
PARTITION BY разбивает данные на сегменты (в данном случае — по пользователю). ORDER BY внутри OVER() задаёт, в каком порядке будут присваиваться номера.DESC. Самая свежая запись получит номер 1 в своём окне:WITH t AS (
SELECT id, user_id, amount,
ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY created_at DESC) AS rn
FROM payments
)
SELECT * FROM t WHERE rn = 1;
CTE (WITH), чтобы сначала пронумеровать строки, а затем отфильтровать только нужный номер.auth_logs(id, user_id, ip, login_at)
WITH t AS (
SELECT id, user_id, ip,
ROW_NUMBER() OVER (PARTITION BY user_id, ip ORDER BY login_at ASC) AS rn
FROM auth_logs
)
SELECT * FROM t WHERE rn = 1;
ROW_NUMBER() подходит, когда нужен номер строки в сегменте, важно выбрать первую/последнюю запись по логике сортировки,требуется топ-N по категориям или пользователям.
☕️ Postgrespro — полная и актуальная документация по PostgreSQL!
SQL-синтаксис, индексы, транзакции, планировщик запросов, репликация, расширения и внутренняя архитектура. Здесь подробно описано не только как писать запросы, но и как база данных работает. Полезно, если используешь Postgres в продакшене или хочешь глубже разобраться в производительности.
📌 Оставляю ссылочку: postgrespro.ru
➡️ SQL Ready | #ресурс
☕️ StrataScratch — вопросы с собеседований!
Готовишься к собеседованиям по SQL или хочешь укрепить свои практические навыки? Этот сайт собрал самые важные вопросы, которые реально встречаются на интервью. Здесь есть и запросы на выборки, агрегаты и JOIN, и открытые задачи, где нужно не просто написать код, а объяснить логику решения.
📌 Оставляю ссылочку: stratascratch.com
➡️ SQL Ready | #ресурс
📂 Напоминалка по SQL Injection (SQLi)!
Например, простая инъекция вроде OR 1=1 может вернуть все данные из таблицы, а blind SQLi позволяет вытаскивать информацию даже тогда, когда приложение не показывает ошибки и результаты запросов.
На картинке — основные типы SQL-инъекций, которые важно знать при работе с базами данных и backend-логикой.
Сохрани, чтобы не забыть!
➡️ SQL Ready | #ресурс
NULL и NOT IN — тонкость SQL, приводящая к логическим ошибкам!
При использовании NOT IN в SQL можно получить логически неверный результат без ошибок выполнения. Причина — трёхзначная логика и наличие NULL в данных.
Представим таблицы:
customers(id)
orders(id, customer_id)
SELECT id
FROM customers
WHERE id NOT IN (
SELECT customer_id
FROM orders
);
NULL, результат этого запроса будет пустым, даже если клиенты без заказов существуют.NOT IN сводится к серии сравнений, а любое сравнение с NULL возвращает неопределённый результат.SELECT id
FROM customers
WHERE id NOT IN (
SELECT customer_id
FROM orders
WHERE customer_id IS NOT NULL
);
NOT EXISTS:SELECT c.id
FROM customers c
WHERE NOT EXISTS (
SELECT 1
FROM orders o
WHERE o.customer_id = c.id
);
NOT EXISTS корректно обрабатывает NULL и предназначен именно для проверок отсутствия связанных строк.NOT EXISTS для анти-джойнов и проверок отсутствия данных, а NOT IN — только при полном контроле результата подзапроса.
📂 Напоминалка по масштабированию баз данных!
Например, индексы ускоряют поиск данных, кэш снижает нагрузку на базу, а шардинг позволяет распределять данные между серверами.
На картинке — 10 техник масштабирования БД, которые стоит держать под рукой при работе с высокими нагрузками.
Сохрани, чтобы не забыть!
➡️ SQL Ready | #ресурс
😎 SQL Style Guide — супер полезный репозиторий для освоения языка!
Практичный ресурс по написанию SQL: как оформлять SELECT, JOIN, CTE, подзапросы и имена таблиц, чтобы запросы были понятными, поддерживаемыми и удобными для работы в команде. Подходит для любых СУБД и реально упрощает работу и учебу.
Оставляю ссылочку: GitHub 📱