SQL Ready | Базы Данных
Авторский канал про Базы Данных и SQL Ресурсы, гайды, задачи, шпаргалки. Информация ежедневно пополняется! Автор: @energy_c РКН: https://clck.ru/3QREBc Реклама на бирже: https://telega.in/c/sql_ready
Больше📈 Аналитический обзор Telegram-канала SQL Ready | Базы Данных
Канал SQL Ready | Базы Данных (@sql_ready) языкового сегмента Русский является активным участником. Сейчас сообщество объединяет 16 610 подписчиков, занимая 7 596 место в категории Технологии и приложения и 39 484 место в регионе Россия.
📊 Показатели аудитории и динамика
С момента создания невідомо проект демонстрирует стремительный рост, собрав аудиторию из 16 610 подписчиков.
Согласно последним данным от 31 августа, 2026, канал показывает стабильную активность. За последние 30 дней изменение числа участников составило 1 234, а за последние 24 часа — 23, при этом общий охват остаётся высоким.
- Статус верификации: Не верифицирован
- Уровень вовлечённости (ER): Средний показатель вовлечённости аудитории составляет 12.62%. В первые 24 часа после публикации контент обычно набирает 6.17% реакций от общего числа подписчиков.
- Охват публикаций: В среднем каждый пост получает 2 097 просмотров. В течение первых суток публикация набирает 1 025 просмотров.
- Реакции и взаимодействия: Аудитория активно поддерживает контент: среднее количество реакций на один пост — 23.
- Тематические интересы: Контент сосредоточен на ключевых темах, таких как sql, строка, users, индекс, user_id.
📝 Описание и контентная политика
Автор описывает ресурс как площадку для выражения субъективного мнения:
“Авторский канал про Базы Данных и SQL
Ресурсы, гайды, задачи, шпаргалки.
Информация ежедневно пополняется!
Автор: @energy_c
РКН: https://clck.ru/3QREBc
Реклама на бирже: https://telega.in/c/sql_ready”
Благодаря высокой частоте обновлений (последние данные получены 01 сентября, 2026) канал поддерживает актуальность и высокий уровень охвата публикаций. Аналитика показывает, что аудитория активно взаимодействует с контентом, что делает его важной точкой влияния в категории Технологии и приложения.
SELECT
u.id,
u.name,
(
SELECT SUM(o.amount)
FROM orders o
WHERE o.user_id = u.id
) AS total_amount
FROM users u;
Если users содержит миллион строк, подзапрос потенциально может быть выполнен миллион раз. Даже при наличии индекса по orders.user_id такой подход иногда становится менее эффективным, особенно в сложных отчётах.
Часто можно сначала агрегировать данные, а затем присоединить результат:
SELECT
u.id,
u.name,
COALESCE(o.total_amount, 0) AS total_amount
FROM users u
LEFT JOIN (
SELECT
user_id,
SUM(amount) AS total_amount
FROM orders
GROUP BY user_id
) o
ON o.user_id = u.id;
Здесь агрегация выполняется один раз, после чего результат соединяется с таблицей пользователей.
Но это не универсальное правило. Современные оптимизаторы умеют преобразовывать некоторые коррелированные подзапросы в более эффективные планы выполнения, поэтому всегда нужно смотреть реальный план через EXPLAIN / EXPLAIN ANALYZE.
Для получения последнего заказа пользователя часто используют оконные функции:
SELECT
user_id,
created_at
FROM (
SELECT
user_id,
created_at,
ROW_NUMBER() OVER (
PARTITION BY user_id
ORDER BY created_at DESC
) AS rn
FROM orders
) t
WHERE rn = 1;
Но и здесь нет универсального решения. При правильном индексе, например:
(user_id, created_at DESC)
коррелированный запрос вида:
SELECT ...
FROM orders
WHERE user_id = ?
ORDER BY created_at DESC
LIMIT 1;
может быть быстрее, потому что база сможет быстро найти одну нужную строку через индекс.
Делаем вывод: коррелированные подзапросы сами по себе не являются ошибкой. Они могут быть как хорошим решением, так и причиной проблем с производительностью — всё зависит от данных, индексов и выбранного плана выполнения.
🔥 В больших отчётах и высоконагруженных API всегда проверяйте фактический план выполнения. Иногда JOIN, предварительная агрегация или оконные функции позволяют значительно уменьшить количество лишних операций.
➡️ SQL Ready | #практикаcity = 'Paris', то country почти всегда будет 'France'. Без этой информации оптимизатор может сильно ошибиться при оценке количества строк и выбрать неудачный план.
EXPLAIN
SELECT *
FROM users
WHERE country = 'France'
AND city = 'Paris';
Вместо того чтобы сразу создавать новый индекс, попробуйте расширенную статистику.
CREATE STATISTICS users_dep (dependencies)
ON country, city
FROM users;
ANALYZE users;
После ANALYZE PostgreSQL сможет учитывать зависимость между колонками и точнее оценивать селективность условий. Во многих случаях этого достаточно, чтобы оптимизатор выбрал более эффективный план выполнения.
🔥 Если запрос фильтрует по нескольким связанным колонкам и оптимизатор ошибается в оценке, сначала попробуйте CREATE STATISTICS, а уже потом решайте, нужен ли новый индекс.
➡️ SQL Ready | #советSELECT и ORDER BY до JOIN, подзапросов, транзакций, индексов, оптимизации запросов и PostgreSQL. Есть структурированные курсы с теорией и практикой.
📌 Оставляю ссылочку: sqllab.ru
➡️ SQL Ready | #ресурсNULL разными значениями. Это означало, что таблица спокойно принимала сколько угодно строк с NULL, даже если на колонке стоял UNIQUE.
CREATE TABLE users (
email text UNIQUE
);
INSERT INTO users VALUES (NULL);
INSERT INTO users VALUES (NULL);
Обе вставки выполнятся успешно.
Если NULL тоже должен быть уникальным, приходилось придумывать обходные пути. Кто-то делал частичные индексы, кто-то использовал COALESCE(), кто-то заводил отдельные флаги.
CREATE TABLE users (
email text,
CONSTRAINT users_email_key
UNIQUE NULLS NOT DISTINCT (email)
);
INSERT INTO users VALUES (NULL);
INSERT INTO users VALUES (NULL);
Вторая вставка уже завершится ошибкой. Для ограничения NULL считается таким же значением, как и любой другой ключ.
CREATE TABLE users (
tenant_id int,
email text,
CONSTRAINT uq_user
UNIQUE NULLS NOT DISTINCT (tenant_id, email)
);
Полезно, когда NULL — это полноценное значение предметной области, а не просто "неизвестно".
🔥 Небольшая возможность PostgreSQL 15, которая позволяет удалить сразу несколько старых костылей вокруг UNIQUE.
➡️ SQL Ready | #совет• Разберётесь, как RAGFlow помогает LLM работать с внутренними документами и снижать количество галлюцинаций;
• Узнаете, чем RAGFlow отличается от классического RAG и как он обрабатывает PDF, таблицы, схемы и сканы;
• Посмотрите, как развернуть RAGFlow и использовать его для баз знаний, техподдержки и аналитики.
🔊 Продолжай читать на Habr!➡️ SQL Ready | #статья
Шпаргалка по механизмам синхронизации параллельных транзакций в PostgreSQL: защита строк от конкурентных изменений и удаления, управление ожиданием и пропуском занятых строк, явная блокировка таблиц и диагностика ожидающих блокировок. Помогает контролировать конкурентный доступ и корректно реализовывать транзакционные сценарии.
➡️ SQL Ready | #шпораSELECT, WHERE и ORDER BY отвечают за выборку, фильтрацию и сортировку данных, JOIN связывает таблицы, а GROUP BY, агрегатные и оконные функции помогают анализировать результаты запросов.
На картинке — структурированная карта SQL: от базовых запросов и объединения таблиц до CTE, подзапросов, DDL/DML/DCL/TCL, транзакций и ограничений целостности данных.
Сохрани, чтобы не потерять!
➡️ SQL Ready | #ресурсstart_at и end_at, проверки пересечений быстро превращаются в набор сравнений. В PostgreSQL для этого есть range types: например, tstzrange для диапазона timestamptz.
Вместо:
WHERE start_at < :end_at
AND end_at > :start_at
можно явно работать с диапазонами:
WHERE tstzrange(start_at, end_at, '[)')
&& tstzrange(:start_at, :end_at, '[)')
Оператор && означает «диапазоны пересекаются». [) задаёт полуинтервал: начало включено, конец исключён, поэтому встреча до 12:00 и следующая с 12:00 не считаются пересекающимися.
Но интереснее то, что PostgreSQL умеет проверять диапазоны и другими операторами:
period @> now() -- содержит момент времени
period && :period -- пересекается
period <@ :period -- находится внутри
Если такие проверки выполняются постоянно, диапазон можно хранить непосредственно в таблице и индексировать GiST:
CREATE INDEX bookings_period_idx
ON bookings USING gist (period);
И самое полезное: правило «для одной комнаты интервалы не должны пересекаться» можно перенести из приложения непосредственно в БД:
CREATE EXTENSION IF NOT EXISTS btree_gist;
ALTER TABLE bookings
ADD CONSTRAINT bookings_no_overlap
EXCLUDE USING gist (
room_id WITH =,
period WITH &&
);
Теперь две пересекающиеся брони одной комнаты физически нельзя записать, даже если два конкурентных запроса одновременно прошли предварительную проверку в приложении.
🔥 Range types превращают интервалы времени из пары колонок и ручной логики в полноценный тип данных: его можно сравнивать, индексировать и даже запретить пересечения на уровне констрейнта.
➡️ SQL Ready | #советGROUP BY и HAVING, JOIN, работа с датами, подзапросы, CTE и оконные функции. Решения автоматически проверяются, а AI-ассистент может дать подсказку, не раскрывая готовый ответ.
📌 Оставляю ссылочку: koddo.ru
➡️ SQL Ready | #ресурсШпаргалка по преобразованию и проверке данных в Oracle: работа со строками, числами, датами, временем и Unicode. Используется для явного преобразования типов, форматирования значений, проверки корректности входных данных и обработки символьных данных.
➡️ SQL Ready | #шпораWITH и обычные подзапросы. Выбор между ними влияет на читаемость запроса, возможность повторного использования данных и работу оптимизатора.
Временная таблица создаётся внутри текущей сессии базы данных и существует до её завершения или до явного удаления. Она подходит для многоэтапной обработки данных, когда результат нужно использовать в нескольких следующих запросах.
CREATE TEMP TABLE monthly_sales AS
SELECT
customer_id,
SUM(amount) AS total_amount
FROM orders
WHERE created_at >= '2026-01-01'
GROUP BY customer_id;
После создания временная таблица становится отдельным объектом базы данных. К ней можно обращаться как к обычной таблице, создавать индексы и выполнять дополнительные операции.
SELECT *
FROM monthly_sales
WHERE total_amount > 10000;
Временные таблицы особенно полезны при сложных процессах обработки данных, где нужно разделить вычисления на несколько этапов и повторно использовать промежуточный результат.
CREATE INDEX idx_monthly_sales_customer_id
ON monthly_sales(customer_id);
CTE (Common Table Expression) создаётся с помощью конструкции WITH и существует только во время выполнения одного SQL-запроса. Он помогает сделать сложную логику более читаемой и структурированной.
WITH monthly_sales AS (
SELECT
customer_id,
SUM(amount) AS total_amount
FROM orders
GROUP BY customer_id
)
SELECT *
FROM monthly_sales
WHERE total_amount > 10000;
В PostgreSQL начиная с версии 12 CTE может быть автоматически встроен оптимизатором в основной запрос. Это называется CTE inlining. В таком случае отдельное промежуточное хранилище данных не создаётся.
WITH active_users AS MATERIALIZED (
SELECT *
FROM users
WHERE status = 'active'
)
SELECT *
FROM active_users;
Основное отличие MATERIALIZED заключается в том, что PostgreSQL принудительно сохраняет результат CTE перед дальнейшей обработкой. Это может быть полезно, если один и тот же результат используется несколько раз или нужно избежать повторного выполнения тяжёлого вычисления.
WITH user_stats AS MATERIALIZED (
SELECT
user_id,
COUNT(*) AS orders_count
FROM orders
GROUP BY user_id
)
SELECT
a.user_id,
a.orders_count
FROM user_stats a
JOIN user_stats b
ON a.user_id = b.user_id;
Однако использование CTE не всегда означает материализацию. PostgreSQL самостоятельно выбирает оптимальный способ выполнения запроса, если не указано MATERIALIZED или NOT MATERIALIZED.
WITH user_stats AS NOT MATERIALIZED (
SELECT
user_id,
COUNT(*) AS orders_count
FROM orders
GROUP BY user_id
)
SELECT *
FROM user_stats;
Если промежуточный результат большой и используется несколько раз в рамках сложного процесса, временная таблица часто подходит лучше. Она позволяет создать индексы, выполнять дополнительные запросы и управлять этапами обработки отдельно.
CREATE TEMP TABLE user_stats AS
SELECT
user_id,
COUNT(*) AS orders_count
FROM orders
GROUP BY user_id;
CREATE INDEX idx_user_stats_user_id
ON user_stats(user_id);
ANALYZE user_stats;
Команда ANALYZE после заполнения временной таблицы помогает PostgreSQL получить актуальную статистику и выбрать более эффективный план выполнения запроса.
Обычный подзапрос существует только внутри конкретного SQL-выражения. Он подходит для локальных вычислений, когда результат нужен только в одном месте и не требуется повторное использование.
SELECT *
FROM (
SELECT
user_id,
COUNT(*) AS orders_count
FROM orders
GROUP BY user_id
) s
WHERE orders_count > 50;
🔥 Выбор подходящего варианта зависит от задачи. CTE обычно используют для повышения читаемости и разделения сложной логики внутри одного запроса. Временные таблицы подходят для многошаговой обработки, больших промежуточных результатов и случаев, когда нужны индексы. Подзапросы удобны для простых локальных вычислений внутри одного SQL-выражения.
➡️ SQL Ready | #практика