This media is not supported in your browser
VIEW IN TELEGRAM
Например, индексы ускоряют поиск данных, а шардинг позволяет распределять нагрузку между несколькими серверами.
На картинке — основные стратегии масштабирования, которые используются в реальных системах.
Сохрани, чтобы держать под рукой!
Please open Telegram to view this post
VIEW IN TELEGRAM
👍13🔥9❤8🤝1
LIMIT без ORDER BY — почему результат нестабилен!
Есть таблица:
И вот такой запрос:
Интуитивно хочется думать, что это первые 10 или последние 10. На деле — это просто неопределённые 10 строк в неопределённом порядке.
Без
Типичный кейс — хочу последние заказы:
Уже лучше: теперь это 10 самых новых по
Но тут есть тонкость — если несколько строк имеют одинаковый
Поэтому обычно добавляют второй критерий:
Если id уникальный — результат становится детерминированным для текущего среза данных. Где это особенно критично: пагинация, API, отчёты, кэш.
Без стабильного порядка начинаются фантомные баги: строки то появляются, то исчезают, то дублируются.
Добавились новые записи — и страницы уже не совпадают с тем, что было секунду назад.
Поэтому в проде чаще используют keyset pagination:
Фактически: дай следующие записи после этой точки.
Работает быстрее и ведёт себя предсказуемо при изменениях данных (Важно: синтаксис с (
И ещё частая ошибка:
Кажется, что это последняя запись, а по факту — самая старая (по умолчанию используется ASC в большинстве СУБД).
🔥 Вся суть:
➡️ SQL Ready | #практика
Есть таблица:
orders(id, customer_id, amount, created_at)
И вот такой запрос:
SELECT * FROM orders LIMIT 10;
Интуитивно хочется думать, что это первые 10 или последние 10. На деле — это просто неопределённые 10 строк в неопределённом порядке.
Без
ORDER BY база не обязана возвращать данные в каком-то фиксированном порядке. Сегодня это один набор строк, завтра — другой. Особенно если поменялся план выполнения или появился индекс.Типичный кейс — хочу последние заказы:
SELECT *
FROM orders
ORDER BY created_at DESC
LIMIT 10;
Уже лучше: теперь это 10 самых новых по
created_at.Но тут есть тонкость — если несколько строк имеют одинаковый
created_at, порядок между ними не детерминирован. Иногда это всплывает в самых неожиданных местах (например, в пагинации).Поэтому обычно добавляют второй критерий:
SELECT *
FROM orders
ORDER BY created_at DESC, id DESC
LIMIT 10;
Если id уникальный — результат становится детерминированным для текущего среза данных. Где это особенно критично: пагинация, API, отчёты, кэш.
Без стабильного порядка начинаются фантомные баги: строки то появляются, то исчезают, то дублируются.
OFFSET и его ограничения:SELECT *
FROM orders
ORDER BY created_at DESC, id DESC
LIMIT 10 OFFSET 20;
Добавились новые записи — и страницы уже не совпадают с тем, что было секунду назад.
Поэтому в проде чаще используют keyset pagination:
SELECT *
FROM orders
WHERE (created_at, id) < ('2026-01-10', 1050)
ORDER BY created_at DESC, id DESC
LIMIT 10;
Фактически: дай следующие записи после этой точки.
Работает быстрее и ведёт себя предсказуемо при изменениях данных (Важно: синтаксис с (
col1, col2) поддерживается не во всех СУБД; универсальный вариант — через OR.)И ещё частая ошибка:
SELECT *
FROM orders
ORDER BY created_at
LIMIT 1;
Кажется, что это последняя запись, а по факту — самая старая (по умолчанию используется ASC в большинстве СУБД).
LIMIT отвечает только за количество. Порядок — это всегда ORDER BY. Без составного индекса (created_at, id) такие запросы на больших таблицах начинают ощутимо тормозить.Please open Telegram to view this post
VIEW IN TELEGRAM
🔥14👍9🤝8❤2
This media is not supported in your browser
VIEW IN TELEGRAM
Этот репозиторий разбирает типичные ошибки и плохие практики в SQL, с которыми сталкиваются разработчики в реальных проектах. Здесь показано, как не стоит писать запросы, и даются более правильные и эффективные альтернативы. Отлично подходит для оптимизации запросов и подготовки к собеседованиям.
Оставляю ссылочку: GitHub📱
Please open Telegram to view this post
VIEW IN TELEGRAM
👍14🤝9🔥8❤2
Например, B-Tree используется в индексах для ускорения поиска, а Hash Table — в механизмах join’ов и кэширования.
На картинке — ключевые структуры данных и типичные сценарии их использования в реальных системах и базах данных.
Сохрани, чтобы держать под рукой!
Please open Telegram to view this post
VIEW IN TELEGRAM
❤13👍9🔥7🤝1
Полуинтервалы вместо BETWEEN для корректных и быстрых диапазонов!
Такой код пропустит всё, что позже '2025-01-31 00:00:00', и это одна из самых частых, незаметных ошибок в аналитике:
Полуинтервал
🔥 Этот паттерн используют в биллинге, аналитике, логах и любых системах, где важна точность временных границ.
➡️ SQL Ready | #совет
BETWEEN кажется удобным, но он включает обе границы, из-за чего легко ловятся баги на датах и времени, особенно с timestamp:WHERE created_at BETWEEN '2025-01-01' AND '2025-01-31'
Такой код пропустит всё, что позже '2025-01-31 00:00:00', и это одна из самых частых, незаметных ошибок в аналитике:
WHERE created_at >= '2025-01-01'
AND created_at < '2025-02-01'
Полуинтервал
[start, end) работает предсказуемо для любых типов времени, не ломается на миллисекундах и хорошо ложится на индексы:WHERE ts >= now()
AND ts < now() + interval '1 day'
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥16❤10👍9
This media is not supported in your browser
VIEW IN TELEGRAM
Репозиторий с материалами для изучения SQL с самого начала: здесь разбираются основы работы с базами данных, синтаксис запросов, JOIN-ы, фильтрация, агрегации и структура таблиц. Формат обучения построен вокруг практики, примеры запросов, задания и объяснения помогают не просто читать теорию, а сразу писать код.
Оставляю ссылочку: GitHub📱
Please open Telegram to view this post
VIEW IN TELEGRAM
❤21🔥10🤝10
This media is not supported in your browser
VIEW IN TELEGRAM
Здесь собраны конспекты, шпаргалки и учебные PDF по всем ключевым темам: от базовых запросов до сложных конструкций и оптимизации. Отдельно выделяется наличие большого количества материалов для подготовки к собеседованиям, сотни вопросов и разборов.
Оставляю ссылочку: GitHub📱
Please open Telegram to view this post
VIEW IN TELEGRAM
👍16❤7🔥7🤝2
UPDATE ... FROM в PostgreSQL: как обновлять данные из другой таблицы и не поймать скрытые дубли!
Задача, которая встречается постоянно: обновить таблицу по данным из другой. Например, проставить клиентам дату последнего заказа.
Есть таблицы:
Интуитивный вариант:
Запрос выполнится, но если у клиента несколько заказов — возникает вопрос: какая именно дата попадёт в
Запрос корректен синтаксически, но логически небезопасен. Если
Поэтому сначала нужно свести соответствие к одной строке на клиента. Через агрегат:
Теперь для каждого клиента ровно одна строка — обновление становится детерминированным.
Вариант через
Здесь тоже выбирается одна строка на клиента за счёт сортировки. Если возможны одинаковые
Коррелированный подзапрос:
Плюс: гарантированно одно значение. Нюанс: обновятся все строки в
Пример ловушки:
С виду безопасно, по факту — та же проблема: соответствие не уникально.
Практическая проверка: замените
Если дубли есть — такой
Помогает и для
🔥 Если
➡️ SQL Ready | #практика
Задача, которая встречается постоянно: обновить таблицу по данным из другой. Например, проставить клиентам дату последнего заказа.
Есть таблицы:
customers(id, last_order_at)
orders(id, customer_id, created_at)
Интуитивный вариант:
UPDATE customers c
SET last_order_at = o.created_at
FROM orders o
WHERE o.customer_id = c.id;
Запрос выполнится, но если у клиента несколько заказов — возникает вопрос: какая именно дата попадёт в
last_order_at? Ответ — это не гарантируется.Запрос корректен синтаксически, но логически небезопасен. Если
JOIN даёт несколько строк для одной записи в customers, PostgreSQL не гарантирует, какую строку он использует при обновлении.Поэтому сначала нужно свести соответствие к одной строке на клиента. Через агрегат:
UPDATE customers c
SET last_order_at = t.max_created_at
FROM (
SELECT
customer_id,
MAX(created_at) AS max_created_at
FROM orders
GROUP BY customer_id
) t
WHERE t.customer_id = c.id;
Теперь для каждого клиента ровно одна строка — обновление становится детерминированным.
Вариант через
DISTINCT ON:UPDATE customers c
SET last_order_at = t.created_at
FROM (
SELECT DISTINCT ON (customer_id)
customer_id,
created_at
FROM orders
ORDER BY customer_id, created_at DESC
) t
WHERE t.customer_id = c.id;
Здесь тоже выбирается одна строка на клиента за счёт сортировки. Если возможны одинаковые
created_at, лучше добавить tie-breaker:ORDER BY customer_id, created_at DESC, id DESC
Коррелированный подзапрос:
UPDATE customers c
SET last_order_at = (
SELECT MAX(o.created_at)
FROM orders o
WHERE o.customer_id = c.id
);
Плюс: гарантированно одно значение. Нюанс: обновятся все строки в
customers, и у клиентов без заказов будет NULL.Пример ловушки:
UPDATE customers c
SET last_order_at = t.created_at
FROM (
SELECT customer_id, created_at
FROM orders
) t
WHERE t.customer_id = c.id;
С виду безопасно, по факту — та же проблема: соответствие не уникально.
Практическая проверка: замените
UPDATE на SELECT с тем же JOIN и посмотрите, есть ли дубли:SELECT c.id, t.*
FROM customers c
JOIN ...
Если дубли есть — такой
UPDATE уже небезопасен. Про индексы:CREATE INDEX idx_orders_customer_created
ON orders (customer_id, created_at);
Помогает и для
MAX, и для ORDER BY. Итог: UPDATE ... FROM — крутой инструмент, но он не проверяет однозначность соответствия.JOIN возвращает несколько строк на одну обновляемую запись, результат не гарантируется. Сначала фиксируем одну строку на ключ — потом обновляем.Please open Telegram to view this post
VIEW IN TELEGRAM
🔥13❤9👍9
Например,
WHERE фильтрует строки до агрегации, а HAVING — уже после GROUP BY.На картинке — основные конструкции: разница между
WHERE и HAVING, оконные функции против обычной агрегации, а также основы партицирования для больших таблиц.Сохрани, чтобы не потерять!
Please open Telegram to view this post
VIEW IN TELEGRAM
👍12🔥9🤝8❤1
Индексы и ORDER BY DESC без лишней сортировки!
Многие думают, что для
В PostgreSQL обычный B-tree индекс:
уже может использоваться для
Если нужен смешанный порядок (например (
🔥 В таких случаях PostgreSQL сможет читать данные сразу в нужном порядке.
➡️ SQL Ready | #совет
Многие думают, что для
ORDER BY … DESC нужен отдельный DESC-индекс — но это не всегда так.В PostgreSQL обычный B-tree индекс:
CREATE INDEX idx_orders_user_created
ON orders (user_id, created_at);
уже может использоваться для
ORDER BY created_at DESC через backward scan, без дополнительной сортировки.Если нужен смешанный порядок (например (
user_id ASC, created_at DESC)), тогда имеет смысл явно указать направление:CREATE INDEX idx_orders_user_created_desc
ON orders (user_id, created_at DESC);
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥16👍11❤10
This media is not supported in your browser
VIEW IN TELEGRAM
Это AI-ассистент для обучения, который позволяет загружать документы, видео или аудио и автоматически превращать их в структурированные материалы: краткие конспекты, ответы, карточки и тесты. Также можно задавать вопросы прямо по загруженному источнику и получать точные ответы на основе его содержания.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍14🔥8🤝8
Уникальность с NULL без триггеров и костылей!
Обычный
Если колонка опциональная, но по смыслу значение всё равно должно быть уникальным, стандартный
Эта форма говорит PostgreSQL считать
То есть второй
Особенно полезно для
🔥
➡️ SQL Ready | #совет
Обычный
UNIQUE в SQL пропускает несколько NULL, потому что NULL не считается равным другому. Из-за этого ограничение часто формально есть, а правило на самом деле не соблюдается:UNIQUE (telegram_id)
Если колонка опциональная, но по смыслу значение всё равно должно быть уникальным, стандартный
UNIQUE даёт дыру в данных.UNIQUE NULLS NOT DISTINCT (telegram_id)
Эта форма говорит PostgreSQL считать
NULL обычным сравнимым значением именно для проверки уникальности.То есть второй
NULL уже не пройдёт, как и дубликат обычного значения.UNIQUE NULLS NOT DISTINCT (tenant_id, external_id)
Особенно полезно для
nullable внешних идентификаторов, one-to-one связей, интеграционных ключей и любых полей, где NULL тоже должен быть единственным допустимым состоянием.UNIQUE NULLS NOT DISTINCT закрывает один из источников грязных данных и заменяет триггеры.Please open Telegram to view this post
VIEW IN TELEGRAM
👍16❤8🔥8
Каждый уровень играет важную роль: от физической передачи сигналов до приложений, с которыми мы взаимодействуем каждый день. Понимание этой модели помогает лучше разбираться в сетевых ошибках, маршрутизации и защите данных.
На картинке — 7 уровней OSI, что делает каждый из них и примеры протоколов.
Сохрани, чтобы не забыть!
Please open Telegram to view this post
VIEW IN TELEGRAM
👍13🔥7🤝7
Проверка качества и целостности данных!
В больших продакшн-базах важно не только находить ошибки, но и структурировать их: проверять NULL, дубликаты, некорректные форматы и аномальные значения.
Сначала выявляем строки с пустыми ключевыми полями:
Проверяем дубликаты по уникальному полю и сразу классифицируем их:
Ищем аномалии в числовых полях (например, сумма заказа < 0):
🔥 Это позволяет отслеживать качество данных, предотвращать ошибки аналитики и готовить отчёты для команды разработки.
➡️ SQL Ready | #практика
В больших продакшн-базах важно не только находить ошибки, но и структурировать их: проверять NULL, дубликаты, некорректные форматы и аномальные значения.
Сначала выявляем строки с пустыми ключевыми полями:
SELECT user_id, email, created_at
FROM users
WHERE user_id IS NULL
OR email IS NULL;
Проверяем дубликаты по уникальному полю и сразу классифицируем их:
SELECT email, COUNT(*) AS cnt,
CASE WHEN COUNT(*)>1 THEN 'Duplicate' ELSE 'Unique' END AS status
FROM users
GROUP BY email;
Ищем аномалии в числовых полях (например, сумма заказа < 0):
SELECT order_id, total_amount
FROM orders
WHERE total_amount < 0;
🔥 Это позволяет отслеживать качество данных, предотвращать ошибки аналитики и готовить отчёты для команды разработки.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤14👍9🤝9
This media is not supported in your browser
VIEW IN TELEGRAM
Если нужно быстро освежить синтаксис или понять суть команд — это то, что нужно. Все основные конструкции, примеры и видеоуроки — коротко и по делу. Отлично подойдёт как шпаргалка и мини‑курс.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10🔥8🤝8❤1
FILTER позволяет задать условие прямо для SUM, COUNT, AVG — без вложенных подзапросов и лишнего шума. Код получается чище, короче и проще читается.Что важно знать:
• FILTER работает внутри агрегата — условие применяется только к нему.
• Отлично подходит для отчётных таблиц с множеством условий.
• Заменяет CASE WHEN в 90% ситуаций, где раньше казалось без него никак.
Поэтому, это инструмент, с которым SQL-запросы становятся короче и понятнее.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥17👍10❤9🤝2