This media is not supported in your browser
VIEW IN TELEGRAM
Если тебе сложно понять алгоритмы по учебникам — этот ресурс решает проблему. Автор объясняет графы, геометрию, деревья, меши из геймдева через понятные визуализации и интерактивы. Сложные идеи здесь раскладываются на простые шаги.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥13❤10👍9
Знали, что NOT IN — главный источник тихих багов, если в подзапросе есть NULL?
Этот запрос выглядит логично, но опасен:
Если подзапрос вернёт хотя бы один
Правильнее и безопаснее паттерн NOT EXISTS:
Он корректно работает при
Хотите повторить? Проверьте разницу сами:
Теперь запустите:
Результат будет пустым.
🔥 А если переписать через
➡️ SQL Ready | #совет
Этот запрос выглядит логично, но опасен:
WHERE user_id NOT IN (SELECT id FROM users);
Если подзапрос вернёт хотя бы один
NULL, условие станет UNKNOWN, и не вернётся ни одной строки.Правильнее и безопаснее паттерн NOT EXISTS:
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, логика вернётся в норму.Please open Telegram to view this post
VIEW IN TELEGRAM
👍21❤11🔥9
Модем отвечает за подключение к провайдеру и получение публичного IP, а роутер управляет локальной сетью: маршрутизирует трафик, выполняет NAT и раздаёт адреса устройствам.
На картинке — ключевые отличия и базовая схема работы.
Сохрани, чтобы не забыть!
Please open Telegram to view this post
VIEW IN TELEGRAM
👍15❤8🤝7🔥1
Please open Telegram to view this post
VIEW IN TELEGRAM
5👍21❤13🔥11👎1
Партицирование в оконных функциях — когда нужно работать с топами внутри групп!
Оконные функции в SQL — стандартный инструмент аналитики. Один из частых кейсов: найти «лучшие» записи внутри каждой группы, не сворачивая таблицу и не теряя строки.
Представим таблицу:
Нужно выбрать самый дорогой товар в каждой категории, но при этом видеть все колонки строки:
Если нужны не только первые, а, например, топ-3 в каждой категории:
Тут важно: без
Оконные функции не требуют
Ещё полезный трюк — находить максимум в группе без
Этот запрос не агрегирует основную таблицу и вернёт несколько строк, если в категории есть товары с одинаковой максимальной ценой (
🔥 Используйте
➡️ 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() нумерует строки внутри каждой партиции, а не по всей таблице.Если нужны не только первые, а, например, топ-3 в каждой категории:
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 в оконных функциях, когда логика должна применяться внутри каждой группы независимо, а строки нужно сохранить целиком.Please open Telegram to view this post
VIEW IN TELEGRAM
👍18❤13🤝7👎1
UPDATE без холостых перезаписей!
Обычный
Если
Это правило можно применить к любым колонкам:
Паттерн остаётся тем же: обновление только при расхождении.
Проверьте сами на тесте:
Запустите 2 раза
🔥
➡️ SQL Ready | #совет
Обычный
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');
Запустите 2 раза
UPDATE сверху, второй раз таблица не изменится и ничего не запишет.UPDATE должен менять только то, что отличается и SQL уже даёт для этого инструменты.Please open Telegram to view this post
VIEW IN TELEGRAM
👍12🔥10❤9
This media is not supported in your browser
VIEW IN TELEGRAM
Если хочешь разобраться с SQL не по документации, а через чёткие объяснения и примеры запросов, этот сайт точно пригодится. Темы здесь идут от базовых до сложных концепций, всё с примерами, которые можно сразу повторить. Удобно, когда нужна практика для проектов или собеседований.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍14🔥11🤝8
Транзакции в 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