Транзакции в SQL — почему частичные изменения хуже ошибки!
Работа с несколькими связанными таблицами в одном сценарии должна быть атомарной. Без
Таблицы:
Сценарий: списать баланс и перевести платёж в
Если соединение обрывается между запросами:
Первое изменение уже сохранено, второе — нет. Итог: деньги списаны, платёж не подтверждён.
Правильный подход — транзакция:
До
Откат при ошибке:
Пока сессия жива, открытая транзакция не откатывается сама по себе и может удерживать блокировки. Автоматический
Нюанс для защиты от гонок и повторной обработки:
Оба
🔥
➡️ SQL Ready | #практика
Работа с несколькими связанными таблицами в одном сценарии должна быть атомарной. Без
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 также работает только в той же транзакции, где будет обновление. Любая операция списания + фиксации платежа = транзакция.Please open Telegram to view this post
VIEW IN TELEGRAM
❤16👍10🔥8
Например, HTTP/2 ускоряет загрузку за счёт мультиплексирования, а HTTP/3 делает обмен ещё быстрее, используя QUIC поверх UDP — уже стандарт для современных браузеров и CDN.
На картинке — ключевые компоненты HTTP-экосистемы, которые важно держать под рукой.
Сохрани, чтобы не забыть!
Please open Telegram to view this post
VIEW IN TELEGRAM
❤15👍11🔥8
Транзакция, которая берёт только свободные строки!
В конкурентной обработке задач важно не брать строку, уже заблокированную другой транзакцией, и не ждать её освобождения.
PostgreSQL делает это через:
Строки, которые уже залочены, исключаются из выборки немедленно, без ожидания.
Хотите повторить интерактивно? Откройте 2 SQL-сессии:
Сессия A:
Сессия B (параллельно):
B никогда не вернёт строку, залоченную A, и не будет ждать, вы увидите разные результаты в разных сессиях.
🔥 База данных сама может быть механизмом синхронизации, если выборка делается с
➡️ SQL Ready | #совет
В конкурентной обработке задач важно не брать строку, уже заблокированную другой транзакцией, и не ждать её освобождения.
PostgreSQL делает это через:
FOR UPDATE SKIP LOCKED
Строки, которые уже залочены, исключаются из выборки немедленно, без ожидания.
Хотите повторить интерактивно? Откройте 2 SQL-сессии:
Сессия A:
BEGIN;
SELECT id FROM jobs WHERE status='queued' FOR UPDATE;
Сессия B (параллельно):
BEGIN;
SELECT id FROM jobs WHERE status='queued' FOR UPDATE SKIP LOCKED LIMIT 1;
B никогда не вернёт строку, залоченную A, и не будет ждать, вы увидите разные результаты в разных сессиях.
SKIP LOCKED. Нет двойной обработки, ожиданий и внешних зависимостей.Please open Telegram to view this post
VIEW IN TELEGRAM
👍13🔥9❤8
This media is not supported in your browser
VIEW IN TELEGRAM
Репозиторий предлагает серию упражнений и заданий на каждый день, которые охватывают ключевые темы: выборки, агрегации, подзапросы, оконные функции и др. Формат один день - одна задача помогает не перегружаться и выстраивать структурированный план обучения. Отлично подходит для практики, подготовки к собеседованиям и укрепления знаний.
Оставляю ссылочку: GitHub📱
Please open Telegram to view this post
VIEW IN TELEGRAM
👍22🔥10🤝7❤1
Find + Update в одном проходе!
Найдём строки с невозможными значениями и сразу подготовим их к
Теперь обновим только найденные строки, не дублируя условие в клиенте:
Ссылаемся на выборку из
Попробуйте сами на тестовой таблице:
Запустите
🔥 Экономит время выравнивания таблиц при интеграциях, корректировки классификаторов или миграций и др.
➡️ SQL Ready | #совет
Найдём строки с невозможными значениями и сразу подготовим их к
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 снова и убедитесь, что исправление точечное и атомарное.Please open Telegram to view this post
VIEW IN TELEGRAM
❤12👍9🔥8
This media is not supported in your browser
VIEW IN TELEGRAM
Если хочешь учиться через практику, этот сайт отличный инструмент. Здесь ты пишешь запросы прямо в браузере, получаешь мгновенную обратную связь и видишь результат. Подойдёт для закрепления теории, подготовки к собеседованию или реальных задач в работе с бд.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍20❤10🔥9
Сравнение наборов и вычисление пересечения по ключу!
Нужно быстро получить пересечение двух таблиц по ключу? Используйте
Выберите только ключи, чтобы исключить лишние проекции и ускорить анализ наборов:
Проверьте сами на интерактивном примере:
Повторите исходный
🔥 Пригодится, когда нужно сверить итерации, найти общие сущности перед миграциями и тд.
➡️ SQL Ready | #совет
Нужно быстро получить пересечение двух таблиц по ключу? Используйте
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 как пересечение наборов.Please open Telegram to view this post
VIEW IN TELEGRAM
👍15🔥10❤9
Например,
Skiplist ускоряет поиск в памяти, Hash-индекс даёт доступ за O(1), а B-tree и LSM-дерево оптимизируют работу с диском и записью.На картинке — 8 структур данных, которые стоит держать под рукой, чтобы понимать, как устроены индексы и хранение в БД.
Сохрани, чтобы не забыть!
Please open Telegram to view this post
VIEW IN TELEGRAM
👍14❤8🔥6🤝4
UNION и UNION ALL — когда строки исчезают без ошибок!
Одинаковые
Для логов полезно явно добавлять источник:
Пересечение (
Если хотите увидеть, какие строки пропадут при
🔥
➡️ SQL Ready | #практика
UNION удаляет дубликаты по всем выбранным колонкам, сравнивая строки целиком, поэтому результат может отличаться от ожиданий.SELECT message FROM logs_app
UNION
SELECT message FROM logs_system;
Одинаковые
message схлопнутся в одну строку, даже если это разные события — ошибки не будет.UNION ALL не удаляет строки из результата запросов, поэтому почти всегда работает быстрее: SELECT message FROM logs_app
UNION ALL
SELECT message FROM logs_system;
Для логов полезно явно добавлять источник:
SELECT 'app' AS src, id, message FROM logs_app
UNION ALL
SELECT 'system' AS src, id, message FROM logs_system
ORDER BY src, id;
Пересечение (
INTERSECT) в MySQL не поддерживается, альтернатива:SELECT DISTINCT a.message
FROM logs_app a
WHERE EXISTS (SELECT 1 FROM logs_system s WHERE s.message = a.message)
LIMIT 10;
Если хотите увидеть, какие строки пропадут при
UNION из-за совпадений между таблицами, используйте UNION ALL и проверяйте строки, встречающиеся в обоих источниках:SELECT message, COUNT(*) AS cnt, COUNT(DISTINCT src) AS sources
FROM (
SELECT message, 'app' AS src FROM logs_app
UNION ALL
SELECT message, 'system' AS src FROM logs_system
) t
GROUP BY message
HAVING sources > 1;
UNION — когда нужна дедупликация, UNION ALL — когда важна каждая строка и производительность.Please open Telegram to view this post
VIEW IN TELEGRAM
👍13🔥9❤7
В этой статье:
• Автор показывает, как хранить и группировать SQL-запросы в одном .sql-файле по сущностям;
• Рассказывается, как использовать go:embed для встраивания этих файлов в бинарник и загружать запросы по имени;
• Представлен парсер, который разбирает .sql с именованными секциями;
• Показаны преимущества подхода: подсветка SQL в IDE, чистый Go-код и др.🔊 Продолжайте читать на Habr!
Please open Telegram to view this post
VIEW IN TELEGRAM
👍13🔥7🤝7
Как выполнять сложные data-миграции, не ломая UNIQUE-ограничения?
Иногда нужно массово менять данные, временно нарушая
Включаем отложенную проверку конкретного ограничения, оно проверится только при
Теперь можно выполнять
Фиксация происходит один раз, если финальное состояние валидно, транзакция коммитится:
Если уникальность нарушена в конце будет
🔥 Отложенные ограничения позволяют безопасно менять данные внутри транзакции, сохраняя целостность и контроль без временного снятия
➡️ SQL Ready | #совет
Иногда нужно массово менять данные, временно нарушая
UNIQUE, но итоговое состояние корректно:BEGIN;
Включаем отложенную проверку конкретного ограничения, оно проверится только при
COMMIT:SET CONSTRAINTS users_email_uniq DEFERRED;
Теперь можно выполнять
UPDATE/INSERT, даже если в процессе появляются дубликаты:UPDATE users
SET email = lower(email);
Фиксация происходит один раз, если финальное состояние валидно, транзакция коммитится:
COMMIT;
Если уникальность нарушена в конце будет
ROLLBACK, без частичных изменений.UNIQUE.Please open Telegram to view this post
VIEW IN TELEGRAM
❤12👍8🔥7
This media is not supported in your browser
VIEW IN TELEGRAM
Материал построен вокруг реальных примеров и практики: от базовых SELECT, JOIN и агрегатов до сложных подзапросов и аналитических функций. Пояснения идут шаг за шагом, с визуальными примерами и задачами, которые помогают сразу закрепить навыки на практике.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥12👍7🤝6❤1
Оконные фреймы (ROWS и RANGE) — управление областью расчёта!
В оконных функциях важны не только
Таблица операций:
Накопительная сумма по пользователю:
При наличии
Если значения
Среднее по последним 3 операциям:
Сумма за последние 7 дней (пример для PostgreSQL):
🔥 Важно помнить:
➡️ SQL Ready | #практика
В оконных функциях важны не только
PARTITION BY и ORDER BY, но и то, какие строки попадают в окно вычисления. За это отвечают оконные фреймы — ROWS и RANGE.Таблица операций:
transactions(id, user_id, amount, created_at)
Накопительная сумма по пользователю:
SUM(amount) OVER (
PARTITION BY user_id
ORDER BY created_at
)
При наличии
ORDER BY и отсутствии явного фрейма в большинстве СУБД используется RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW.Если значения
created_at совпадают, сумма считается сразу по группе строк (peers).Среднее по последним 3 операциям:
AVG(amount) OVER (
PARTITION BY user_id
ORDER BY created_at, id
ROWS BETWEEN 2 PRECEDING AND CURRENT ROW
)
ROWS формирует окно по количеству строк. Детерминированный ORDER BY необходим для воспроизводимого результата.Сумма за последние 7 дней (пример для PostgreSQL):
SUM(amount) OVER (
PARTITION BY user_id
ORDER BY created_at
RANGE BETWEEN INTERVAL '7 days' PRECEDING AND CURRENT ROW
)
RANGE формирует окно по значениям ORDER BY. Поддержка и синтаксис интервалов зависят от СУБД; часто допускается только одно выражение в ORDER BY.ROWS — предсказуем по количеству строк, RANGE — удобен для временных интервалов и peer-групп, неявный фрейм может менять результат вычисленийPlease open Telegram to view this post
VIEW IN TELEGRAM
❤11👍10🔥8
Согласованное чтение данных внутри одной транзакции!
Иногда несколько
В PostgreSQL это фиксирует
Все последующие
Это гарантирует согласованность результатов между запросами без блокировки пишущих транзакций:
🔥 После
➡️ SQL Ready | #совет
Иногда несколько
SELECT должны работать с одной и той же версией данных, даже если параллельно идут изменения.BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ;
В PostgreSQL это фиксирует
MVCC snapshot в момент первого statement внутри транзакции:SELECT COUNT(*) FROM orders;
Все последующие
SELECT читают один и тот же snapshot и не видят новые COMMIT из других сессий, при этом собственные изменения транзакции видны:SELECT SUM(amount) FROM orders;
Это гарантирует согласованность результатов между запросами без блокировки пишущих транзакций:
COMMIT;
COMMIT snapshot освобождается, транзакция завершается.Please open Telegram to view this post
VIEW IN TELEGRAM
❤10🔥9👍8
Например,
1NF требует атомарных значений, 2NF убирает частичные зависимости, а 3NF избавляет от транзитивных зависимостей.На картинке — основные нормальные формы, которые полезны при проектировании SQL-баз данных.
Сохрани, чтобы не забыть!
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥13👍9🤝7❤1
EXPLAIN — узнаём, как СУБД реально выполняет ваш запрос!
Команда
Допустим, у нас есть запрос:
Запускаем
Если видим
Чтобы ускорить выполнение, создаём индекс:
🔥 Теперь при повторном
➡️ SQL Ready | #практика
Команда
EXPLAIN показывает, что делает база данных под капотом при выполнении SQL-запроса. Это помогает найти узкие места и понять, почему запрос может работать медленно.Допустим, у нас есть запрос:
SELECT * FROM books WHERE author = 'Толстой';
Запускаем
EXPLAIN, чтобы посмотреть план выполнения:EXPLAIN SELECT * FROM books WHERE author = 'Толстой';
Если видим
Table Scan или Seq Scan — это означает, что происходит полный просмотр таблицы. Такой способ может быть медленным, особенно при большом объёме данных.Чтобы ускорить выполнение, создаём индекс:
CREATE INDEX idx_author ON books(author);
EXPLAIN запрос может использовать Index Scan, что значительно быстрее.Please open Telegram to view this post
VIEW IN TELEGRAM
🔥13👍10❤8
This media is not supported in your browser
VIEW IN TELEGRAM
Вводишь любую команду в терминале, и он по частям объясняет, что делает каждая часть. Не просто man-ка, а понятный синтакс-анализ.
Особенно кайф для тех, кто работает в
Linux/DevOps/CI среде и хочет разбираться, а не наугад копипастить из StackOverflow.Please open Telegram to view this post
VIEW IN TELEGRAM
👍13🔥9🤝9
Когда в запросе нужны 2-3 конкретных поля, база может отдать их прямо из индекса, не трогая таблицу. Это особенно важно для тяжёлых таблиц, где каждый лишний lookup - потеря времени.
Сегодня в гайде:
• Как запрос выполняется только из индекса;
• Как убедиться, что таблица не читается (Heap Fetches: 0 в плане);
• Как проектировать индексы, чтобы покрывать SELECT полностью.
Покрывающий индекс устраняет table lookup, снижает I/O и делает чтение стабильным при росте данных.
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥15❤8👍6🤝1