sql_ready | Unsorted

Telegram-канал sql_ready - SQL Ready | Базы Данных

7786

Авторский канал про Базы Данных и SQL Ресурсы, гайды, задачи, шпаргалки. Информация ежедневно пополняется! Автор: @energy_it

Subscribe to a channel

SQL Ready | Базы Данных

❤️ SQL-шпаргалка — основные конструкции и приёмы работы с базами данных!

Справочник по SQL с примерами запросов и пояснениями. Здесь на небольших таблицах разобраны INNER, LEFT, RIGHT, FULL и CROSS JOIN, а также показаны различия синтаксиса между PostgreSQL, MySQL, SQLite и SQL Server. Для команд указано, что именно они делают и в каких ситуациях применяются.

📌 Оставляю ссылочку: tools.sitebyme.ru

➡️ SQL Ready | #ресурс

Читать полностью…

SQL Ready | Базы Данных

🖥 PostgreSQL — управление последовательностями!

Шпаргалка по работе с последовательностями в PostgreSQL: создание и удаление sequence, получение новых и текущих значений, сброс и синхронизация счётчика после импорта, а также привязка последовательности к столбцу. Помогает управлять генерацией идентификаторов и корректно работать со счётчиками при конкурентных вставках и загрузке данных.

➡️ SQL Ready | #шпора

Читать полностью…

SQL Ready | Базы Данных

Настройки только для одного запроса!

Необязательно менять statement_timeout, work_mem или другие параметры для всей сессии. SET LOCAL действует только до конца текущей транзакции.

BEGIN;

SET LOCAL lock_timeout = '500ms';

ALTER TABLE orders
ADD COLUMN source text;

COMMIT;


Так миграция не будет бесконечно ждать блокировку: если таблица занята дольше заданного времени, PostgreSQL завершит операцию ошибкой.
BEGIN;

SET LOCAL work_mem = '512MB';

SELECT customer_id, count(*)
FROM events
GROUP BY customer_id;

COMMIT;


Можно даже точечно дать тяжёлому запросу больше памяти, не увеличивая work_mem для остальных запросов соединения.

🔥 SET LOCAL позволяет тюнить PostgreSQL под конкретную операцию и автоматически возвращает настройки назад после COMMIT или ROLLBACK.

➡️ SQL Ready | #совет

Читать полностью…

SQL Ready | Базы Данных

Почему OFFSET деградирует на больших таблицах!

OFFSET часто используют для пагинации, потому что запрос выглядит просто. На небольших таблицах проблем обычно нет, но на больших объёмах стоимость такого подхода растёт вместе с глубиной страницы.

Есть таблица:

events(
id BIGINT,
user_id BIGINT,
payload JSONB,
created_at TIMESTAMPTZ
)


Типичная пагинация:
SELECT
id,
user_id,
created_at
FROM events
ORDER BY created_at DESC
LIMIT 50 OFFSET 1000000;


Кажется, что база должна просто пропустить миллион строк и вернуть следующие 50. Но SQL-движок не может сделать настоящий прыжок через OFFSET. Ему нужно обработать строки до нужной позиции, а потом отбросить их.

Без подходящего индекса это может выглядеть так: база читает строки, определяет порядок сортировки, обрабатывает OFFSET + LIMIT записей, выбрасывает ненужные строки и возвращает только нужный результат.

Даже если есть индекс:
CREATE INDEX idx_events_created_at
ON events(created_at DESC);


ситуация всё равно не идеальна.

Индекс помогает быстрее читать данные в нужном порядке, но базе всё равно приходится пройти большое количество записей, чтобы добраться до нужного OFFSET.

Например:
LIMIT 50 OFFSET 1000000;


означает, что базе нужно обработать примерно миллион строк перед тем, как вернуть результат.

Для глубоких страниц обычно используют keyset pagination (cursor pagination). Вместо номера страницы передаётся последнее значение из предыдущего результата:
SELECT
id,
user_id,
created_at
FROM events
WHERE created_at < '2026-08-01 12:00:00'
ORDER BY created_at DESC
LIMIT 50;


Теперь база может использовать индекс и сразу искать позицию, с которой нужно продолжить чтение.

Но одного created_at недостаточно, если несколько событий имеют одинаковое время.

Например:
2026-08-01 12:00:00

2026-08-01 12:00:00

2026-08-01 12:00:00


Порядок становится неоднозначным. Поэтому добавляют уникальный ключ:
CREATE INDEX idx_events_cursor
ON events(created_at DESC, id DESC);


И запрос становится:
SELECT
id,
user_id,
created_at
FROM events
WHERE (created_at, id) < ('2026-08-01 12:00:00', 1500000)
ORDER BY created_at DESC, id DESC
LIMIT 50;


Теперь курсор точно определяет позицию в индексе.

Главное преимущество такого подхода — стоимость запроса зависит в основном от размера страницы, а не от глубины пагинации. Первая страница:
LIMIT 50;


и страница после миллионов записей:
WHERE (created_at, id) < (...)
LIMIT 50;


используют один и тот же принцип: найти позицию в B-tree индексе и продолжить чтение.

OFFSET остаётся нормальным решением для административных интерфейсов, внутренних инструментов и небольших таблиц. Но для лент событий, истории операций, логов и больших списков он быстро становится узким местом.

🔥 Делаем вывод: OFFSET удобен для разработки, но плохо масштабируется на больших объёмах данных. Для больших таблиц лучше использовать keyset pagination с составным индексом и стабильным курсором.

➡️ SQL Ready | #практика

Читать полностью…

SQL Ready | Базы Данных

😍 zasqlpython — платформа для изучения и практики SQL!

Сайт позволяет изучать SQL с нуля и сразу закреплять материал на практике. Бесплатный курс включает 10 уроков и 92 задачи с автоматической проверкой прямо в браузере. После базового курса можно перейти к SQL-тренажёру с сотнями задач повышенной сложности и заданиями в формате собеседований.

📌 Оставляю ссылочку: zasqlpython.ru

➡️ SQL Ready | #ресурс

Читать полностью…

SQL Ready | Базы Данных

Почему ctid нельзя использовать как постоянный идентификатор!

В PostgreSQL каждая строка имеет системную колонку ctid. Она содержит физический адрес текущей версии строки в таблице: номер страницы и позицию строки внутри этой страницы.

Иногда ctid используют для поиска, удаления или диагностики отдельных записей, но важно понимать, что это не постоянный идентификатор строки. Значение ctid может измениться в процессе обычной работы базы данных, поэтому использовать его в прикладной логике нельзя.

Для начала создадим простую таблицу с первичным ключом и несколькими тестовыми записями, чтобы наглядно проследить, как изменяется значение ctid.

CREATE TABLE users (
id INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
name TEXT
);


Теперь добавим несколько строк, с которыми будем работать в дальнейших примерах.
INSERT INTO users (name)
VALUES
('Alice'),
('Bob'),
('Charlie');


Посмотрим, какое значение ctid PostgreSQL присвоил каждой записи после вставки.
SELECT
ctid,
id,
name
FROM users;


Результат может выглядеть так:
ctid  | id | name
------+----+--------
(0,1) | 1 | Alice
(0,2) | 2 | Bob
(0,3) | 3 | Charlie


Теперь изменим одну из строк. На первый взгляд кажется, что PostgreSQL просто обновит существующую запись, однако механизм хранения данных работает иначе.
UPDATE users
SET name = 'Robert'
WHERE id = 2;


После выполнения UPDATE снова посмотрим значения ctid и сравним их с предыдущим результатом.
SELECT
ctid,
id,
name
FROM users;


Теперь можно увидеть, что значение ctid изменилось. Например:
ctid  | id | name
------+----+---------
(0,1) | 1 | Alice
(0,4) | 2 | Robert
(0,3) | 3 | Charlie


Это происходит из-за механизма MVCC. При выполнении UPDATE PostgreSQL не изменяет строку на месте, а создаёт её новую версию, которая получает новый физический адрес (ctid). Старая версия строки некоторое время остаётся в таблице и может быть видима другим транзакциям в зависимости от их снимка данных.

Изменение ctid происходит не только при UPDATE. Любые операции, которые физически переписывают таблицу, также приводят к изменению физических адресов строк. Например:
VACUUM FULL users;


или
CLUSTER users USING users_pkey;


Поэтому использовать ctid в качестве внешнего ключа, хранить его в приложении или считать постоянным идентификатором записи нельзя.
При этом ctid остаётся полезным инструментом для служебных задач. Один из самых распространённых случаев — удалить одну запись среди полностью одинаковых дубликатов, когда значения всех пользовательских столбцов совпадают и отличить строки обычными средствами невозможно.

Например, создадим отдельную таблицу без ограничений уникальности:
CREATE TABLE duplicate_users (
name TEXT
);


Добавим одинаковые строки:
INSERT INTO duplicate_users (name)
VALUES
('Alice'),
('Alice'),
('Bob');


Удалим только одну из двух одинаковых строк:
DELETE
FROM duplicate_users
WHERE ctid = (
SELECT ctid
FROM duplicate_users
WHERE name = 'Alice'
LIMIT 1
);


В результате останется одна строка с именем Alice. В этом примере ctid определяется и используется в рамках одного SQL-запроса, поэтому используется актуальный физический адрес версии строки и не возникает проблемы с использованием устаревшего значения.

🔥 ctid — это физический адрес текущей версии строки, а не её постоянный идентификатор. Для связи данных всегда используйте первичный ключ, а ctid оставьте для диагностических и служебных операций.

➡️ SQL Ready | #практика

Читать полностью…

SQL Ready | Базы Данных

🐱 Нашел крайне занимательную статью на Хабре: «Условная агрегация в SQL: ускоряем отчеты, избавляясь от лишних JOIN-ов и подзапросов»!

В этой статье:
• Узнаете, как ускорять сложные SQL-запросы с помощью условной агрегации;
• Разберёте применение CASE и FILTER вместо множества подзапросов и JOIN-ов;
• Посмотрите на примерах, как сделать SQL-код быстрее, чище и проще для поддержки.

🔊 Продолжай читать на Habr!


➡️ SQL Ready | #статья

Читать полностью…

SQL Ready | Базы Данных

Почему коррелированные подзапросы могут снижать производительность SQL-запроса!

Коррелированные подзапросы удобны: внутри них можно обращаться к значениям текущей строки внешнего запроса.

Проблема в том, что оптимизатор может выбрать план, при котором такой подзапрос будет выполняться повторно для каждой строки внешней выборки. На больших объёмах данных это может стать узким местом. Например:

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 | #практика

Читать полностью…

SQL Ready | Базы Данных

Научите оптимизатор понимать ваши данные!

PostgreSQL по умолчанию считает, что значения в разных колонках независимы друг от друга. Но в реальных данных это часто не так.

Например, если 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 | #совет

Читать полностью…

SQL Ready | Базы Данных

UNIQUE и NULL в PostgreSQL 15!

До PostgreSQL 15 уникальные ограничения считали 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 | #совет

Читать полностью…

SQL Ready | Базы Данных

📂 Шпаргалка по нормализации баз данных в MySQL!

Например, 1NF требует атомарных значений, 2NF избавляет от частичных зависимостей, а 3NF — от транзитивных. Для более сложных схем пригодятся BCNF и 4NF.

На картинке — основные нормальные формы с требованиями, примерами и пользой каждой из них.

Сохрани, чтобы не потерять!

➡️ SQL Ready | #ресурс

Читать полностью…

SQL Ready | Базы Данных

👨‍💻 Junior Database — база вопросов и ответов по SQL и базам данных!

В репозитории собраны 27 тем, которые часто встречаются при изучении баз данных и подготовке к техническим собеседованиям: транзакции и ACID, нормализация и денормализация, первичные и внешние ключи, JOIN, GROUP BY и HAVING, индексы, миграции, хранимые процедуры и триггеры. Также затрагиваются оптимизация запросов, партицирование, репликация, шардинг и различия между SQL и NoSQL.

Оставляю ссылочку: GitHub 📱

➡️ SQL Ready | #репозиторий

Читать полностью…

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 | #совет

Читать полностью…

SQL Ready | Базы Данных

🖥 Oracle — преобразование и проверка данных!

Шпаргалка по преобразованию и проверке данных в Oracle: работа со строками, числами, датами, временем и Unicode. Используется для явного преобразования типов, форматирования значений, проверки корректности входных данных и обработки символьных данных.

➡️ SQL Ready | #шпора

Читать полностью…

SQL Ready | Базы Данных

📂 Напоминалка по SQL JOIN!

Например, SEMI JOIN позволяет получить строки, для которых есть совпадение в другой таблице, ANTI JOIN — найти строки без совпадений, а NATURAL JOIN автоматически соединяет таблицы по одноимённым столбцам.

На картинке — наглядное сравнение трёх подходов: SEMI JOIN через EXISTS, ANTI JOIN через NOT EXISTS и NATURAL JOIN, а также показано, чем SEMI JOIN отличается от обычного INNER JOIN.

Сохрани, чтобы не потерять!

➡️ SQL Ready | #ресурс

Читать полностью…

SQL Ready | Базы Данных

Проверяйте преобразование без исключений!

Обычный cast падает с ошибкой, если значение нельзя преобразовать. Из-за этого в ETL и в запросах к промежуточным данным часто приходится заранее чистить данные или писать PL/pgSQL с обработкой исключений.

SELECT value::integer
FROM staging;
-- ERROR при первом плохом значении


PostgreSQL умеет проверять, является ли строка допустимым значением конкретного типа, не вызывая ошибку.
SELECT value
FROM staging
WHERE pg_input_is_valid(value, 'integer');


Типом может быть не только integer:
SELECT pg_input_is_valid('192.168.1.10', 'inet');
SELECT pg_input_is_valid('550e8400-e29b-41d4-a716-446655440000', 'uuid');
SELECT pg_input_is_valid('2026-09-08', 'date');


А pg_input_error_info() позволяет получить причину, почему преобразование невозможно.
SELECT *
FROM pg_input_error_info('2026-02-30', 'date');


🔥 pg_input_is_valid() позволяет валидировать грязные входные данные средствами самой системы типов PostgreSQL.

➡️ SQL Ready | #совет

Читать полностью…

SQL Ready | Базы Данных

😎 PostgreSQL FAQ — справочник по частым проблемам и вопросам!

Здесь собраны разборы типичных ситуаций при работе с PostgreSQL: проблемы с подключением и настройкой, ошибки в SQL, оптимизация медленных запросов, партиционирование, размеры таблиц, timestamp with time zone, pg_dump и другие нюансы. Есть конкретные команды, примеры диагностики и рекомендации по тому, какие данные собирать для поиска проблем.

Оставляю ссылочку: GitHub 📱


➡️ SQL Ready | #репозиторий

Читать полностью…

SQL Ready | Базы Данных

✍️ Попалась интересная статья на Хабре: «Почему в БД на PostgreSQL популярен тип numeric?»!

В этой статье:
• Разберётесь, почему для денег и точных расчётов часто выбирают numeric, несмотря на его производительность;
• Узнаете, чем на практике отличаются numeric, целые типы и double precision;
• Посмотрите, какие требования к точности и округлению предъявляют SQL, платёжные системы и финансовые стандарты.

🔊 Продолжай читать на Habr!


➡️ SQL Ready | #статья

Читать полностью…

SQL Ready | Базы Данных

📂 Шпаргалка по снижению Latency в Backend-системах!

Например, Cache позволяет отдавать часто используемые данные без обращения к базе данных, а Load Balancer распределяет запросы между несколькими серверами, повышая скорость и отказоустойчивость приложения.

На картинке — основные стратегии уменьшения задержек в высоконагруженных системах.

Сохрани, чтобы не потерять!

➡️ SQL Ready | #ресурс

Читать полностью…

SQL Ready | Базы Данных

🖥 MySQL — работа с NULL!

Шпаргалка по обработке NULL в MySQL: подстановка резервных значений, проверка наличия и отсутствия данных, условная обработка, безопасные вычисления и сравнение nullable-значений. Помогает учитывать семантику NULL и избегать неочевидного поведения в условиях, выражениях и вычислениях.

➡️ SQL Ready | #шпора

Читать полностью…

SQL Ready | Базы Данных

7,2 млн рублей призового фонда и реальные задачи космической отрасли 🚀

В сентябре пройдет серия КосмоХакатонов для студентов, молодых ученых и специалистов.
Участникам предстоит за два дня разработать собственное решение, поработать с экспертами и представить проект жюри.

Участников ждут:
🛰 реальные задачи космической отрасли
👥 команды от 3 до 5 человек
💻 очный и онлайн-форматы
🧑‍💻 работа с экспертами и трекерами
🏆 финал в Москве

Первый КосмоХакатон стартует уже 4 сентября в Ростове-на-Дону.

Дальше серия продолжится в Красноярске, Нижнем Новгороде, Благовещенске и Санкт-Петербурге, а завершится финалом в Москве.

Участие бесплатное. Присоединиться могут студенты, аспиранты, молодые ученые и специалисты от 18 лет.
🔗 Зарегистрироваться: https://космохакатон.рф

Читать полностью…

SQL Ready | Базы Данных

✍️ Архитектура высоконагруженных систем — подробный материал по проектированию Highload!

Здесь разобраны ключевые вещи, с которыми сталкиваются при разработке нагруженных систем: RPS, latency и throughput, вертикальное и горизонтальное масштабирование, индексы, репликация и шардирование баз данных, кеширование, брокеры сообщений и др. Есть практические примеры с MySQL, PostgreSQL, Kafka и Tarantool, а также инструменты для тестирования и мониторинга.

Оставляю ссылочку: GitHub 📱


➡️ SQL Ready | #репозиторий

Читать полностью…

SQL Ready | Базы Данных

📂 Шпаргалка по Backend-разработке!

Например, REST используется для построения API, Redis помогает кэшировать данные, а Docker позволяет упаковать приложение вместе со всеми его зависимостями.

На картинке — основные направления Backend-разработки: языки программирования, базы данных, API, авторизация, серверы, контейнеризация, CI/CD и мониторинг. Полезная карта того, что стоит изучить Backend-разработчику.

Сохрани, чтобы не потерять!

➡️ SQL Ready | #ресурс

Читать полностью…

SQL Ready | Базы Данных

🤔 SQL Lab — интерактивная платформа для изучения и практики SQL!

Сайт для тех, кто хочет освоить SQL через работу с запросами. Код пишется прямо в браузере: выполняете запрос, сразу видите результат и получаете автоматическую проверку решения. Обучение построено от базовых SELECT и ORDER BY до JOIN, подзапросов, транзакций, индексов, оптимизации запросов и PostgreSQL. Есть структурированные курсы с теорией и практикой.

📌 Оставляю ссылочку: sqllab.ru

➡️ SQL Ready | #ресурс

Читать полностью…

SQL Ready | Базы Данных

❤️ Интересная статья на Хабре: «Что такое RAGFlow и с чем его едят»!

В этой статье:
• Разберётесь, как RAGFlow помогает LLM работать с внутренними документами и снижать количество галлюцинаций;
• Узнаете, чем RAGFlow отличается от классического RAG и как он обрабатывает PDF, таблицы, схемы и сканы;
• Посмотрите, как развернуть RAGFlow и использовать его для баз знаний, техподдержки и аналитики.

🔊 Продолжай читать на Habr!


➡️ SQL Ready | #статья

Читать полностью…

SQL Ready | Базы Данных

🖥 PostgreSQL — блокировки строк и конкурентный доступ!

Шпаргалка по механизмам синхронизации параллельных транзакций в PostgreSQL: защита строк от конкурентных изменений и удаления, управление ожиданием и пропуском занятых строк, явная блокировка таблиц и диагностика ожидающих блокировок. Помогает контролировать конкурентный доступ и корректно реализовывать транзакционные сценарии.

➡️ SQL Ready | #шпора

Читать полностью…

SQL Ready | Базы Данных

📂 SQL в одной шпаргалке!

Например, SELECT, WHERE и ORDER BY отвечают за выборку, фильтрацию и сортировку данных, JOIN связывает таблицы, а GROUP BY, агрегатные и оконные функции помогают анализировать результаты запросов.

На картинке — структурированная карта SQL: от базовых запросов и объединения таблиц до CTE, подзапросов, DDL/DML/DCL/TCL, транзакций и ограничений целостности данных.

Сохрани, чтобы не потерять!

➡️ SQL Ready | #ресурс

Читать полностью…

SQL Ready | Базы Данных

👨‍💻 Koddo — сайт с теорией и практикой для обучения!

Платформа для изучения SQL через решение реальных задач прямо в браузере. На практике разбираются выборки и фильтрация, GROUP BY и HAVING, JOIN, работа с датами, подзапросы, CTE и оконные функции. Решения автоматически проверяются, а AI-ассистент может дать подсказку, не раскрывая готовый ответ.

📌 Оставляю ссылочку: koddo.ru

➡️ SQL Ready | #ресурс

Читать полностью…

SQL Ready | Базы Данных

Временные таблицы: различия между TEMP, CTE и материализацией данных!

В SQL существует несколько способов работать с промежуточными результатами. Основные варианты — временные таблицы, CTE через 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 | #практика

Читать полностью…

SQL Ready | Базы Данных

Вычисляемые значения на стороне PostgreSQL!

Если значение полностью зависит от других колонок, не обязательно считать его перед каждым INSERT и UPDATE.

PostgreSQL умеет делать это сам и всегда гарантирует корректный результат.

INSERT INTO orders(price, quantity)
VALUES (100, 3);

SELECT total
FROM orders
WHERE id = 1;


Поле total заполнится автоматически. Его нельзя случайно забыть обновить или вычислить по старой формуле.
UPDATE orders
SET quantity = 5
WHERE id = 1;

SELECT total
FROM orders
WHERE id = 1;


После изменения исходных данных значение пересчитается автоматически.
ALTER TABLE products
ADD COLUMN search_name text
GENERATED ALWAYS AS (lower(name)) STORED;


Это удобно для нормализованных значений, поисковых ключей, вычисляемых сумм и любых других детерминированных данных, которые должны всегда оставаться консистентными.

🔥 Если колонка полностью вычисляется из других колонок, пусть этим занимается PostgreSQL. Логику проще поддерживать, когда вычисление в одном месте.

➡️ SQL Ready | #совет

Читать полностью…
Subscribe to a channel