SQL Academy: всё о реляционных БД и SQL
По всем вопросам и коммерческим предложениям писать @LadanovNick Купить рекламу: https://telega.in/c/sqlacademyofficial Чат студентов SQL Academy https://t.me/sqlacademyorg
نمایش بیشتر📈 تحلیل کانال تلگرام SQL Academy: всё о реляционных БД и SQL
کانال SQL Academy: всё о реляционных БД и SQL (@sqlacademyofficial) در بخش زبانی روسی بازیگری فعال است. در حال حاضر جامعه شامل 11 363 مشترک است و جایگاه 10 911 را در دسته فناوری و برنامهها و رتبه 57 339 را در منطقه روسيا دارد.
📊 شاخصهای مخاطب و پویایی
از زمان ایجاد در невідомо، پروژه رشد سریعی داشته و 11 363 مشترک جذب کرده است.
بر اساس آخرین دادهها در تاریخ 27 ژوئن, 2026، کانال فعالیت پایداری دارد. در ۳۰ روز گذشته تغییر اعضا برابر 173 و در ۲۴ ساعت گذشته برابر 1 بوده و همچنان دسترسی گستردهای حفظ شده است.
- وضعیت تأیید: تأیید نشده
- نرخ تعامل (ER): میانگین تعامل مخاطب 17.59% است و در ۲۴ ساعت نخست پس از انتشار، محتوا معمولاً N/A% واکنش نسبت به کل مشترکان کسب میکند.
- دسترسی پستها: هر پست به طور میانگین 1 997 بازدید دریافت میکند. در اولین روز معمولاً 0 بازدید جمعآوری میشود.
- واکنشها و تعامل: مخاطبان بهطور فعال حمایت میکنند؛ میانگین واکنش به هر پست 16 است.
- علایق موضوعی: محتوا بر موضوعات کلیدی مانند sql, строка, индекс, auto_increment, created_at تمرکز دارد.
📝 توضیح و سیاست محتوایی
نویسنده این فضا را محل بیان دیدگاههای شخصی توصیف میکند:
“По всем вопросам и коммерческим предложениям писать @LadanovNick
Купить рекламу: https://telega.in/c/sqlacademyofficial
Чат студентов SQL Academy
https://t.me/sqlacademyorg”
به لطف بهروزرسانیهای پرتکرار (آخرین داده در تاریخ 28 ژوئن, 2026)، کانال همواره بهروز و دارای دسترسی بالاست. تحلیلها نشان میدهد مخاطبان بهطور فعال با محتوا تعامل دارند و آن را به نقطه اثرگذاری مهم در دسته فناوری و برنامهها تبدیل کردهاند.
NTILE(N) OVER (PARTITION BY … ORDER BY …)
🔹 N — число групп (4 = квартели).
🔹 PARTITION BY (необязательно) — создаёт независимые группы (например, по стране).
🔹 ORDER BY — признак, по которому сортируем и считаем ранг.
2️⃣ Классический пример: 4 квартиля по количеству заказов
SELECT
user_id,
orders_count,
NTILE(4) OVER
(ORDER BY orders_count DESC) AS quartile
FROM user_stats
ORDER BY orders_count DESC;
🔹 Пользователи с наибольшим orders_count попадают в quartile = 1, а с наименьшим — в quartile = 4.
🔹 Если строк не делится поровну, верхние группы получат на 1 запись больше (MySQL делит «сверху»).
3️⃣ Квартели внутри каждой страны
SELECT
country,
user_id,
orders_count,
NTILE(4) OVER (
PARTITION BY country
ORDER BY orders_count DESC
) AS quartile
FROM user_stats;
Теперь каждый блок «страна» делится на свои 4 части — удобно для локальных лидеров.
4️⃣ Как использовать результат
🔹Маркетинг: таргетировать акции только quartile = 4 (самые неактивные).
🔹Аналитика: сравнить средний чек между квартилями.
🔍 Потренируйтесь
Откройте готовый плейграунд, запустите NTILE(4) и поэкспериментируйте с разным числом групп.
👉 https://sqlplayground.app/sandbox/683ef210cb9fcbe8d3db3a9e
✅ Итог
🔹NTILE(N) быстро делит данные на равные сегменты.
🔹Работает вместе с PARTITION BY и любой сортировкой.
🔹Незаменим при сегментации пользователей, товаров или чеков.
-- страница 3, по 20 записей
SELECT *
FROM posts
ORDER BY created_at DESC
LIMIT 20 OFFSET 40;
Работает просто, но есть три проблемы:
🔹 OFFSET N сначала пропускает N строк → чем дальше, тем медленнее.
🔹 Если за время прокрутки добавятся новые посты, пользователь увидит дубликаты или пропуски.
🔹При больших значениях OFFSET сервер читает тысячи строк зря.
2️⃣ Key-set pagination (a.k.a. «лента без дыр»)
Идея: вместо «пропустить N» передаём последний id/дату уже загруженной записи и берём следующие сверху.
-- первый запрос (стартовая лента)
SELECT *
FROM posts
ORDER BY created_at DESC
LIMIT 20;
-- фронт получает последнюю дату
→ next_cursor = '2025-05-26 10:15:00'
-- второй запрос (следующая порция)
SELECT *
FROM posts
WHERE created_at < '2025-05-26 10:15:00'
ORDER BY created_at DESC
LIMIT 20;
Плюсы:
✅ Нет медленного OFFSET — используется индекс по created_at.
✅ Новые посты не «вставляются» в уже просмотренную часть, дубликатов нет.
✅ Маркер-курсор можно прятать в URL или JSON‐ответе.
3️⃣ Что передавать в качестве курсора?
🔹 Авто-инкремент id — легко, но если бывают «дыры» (удаления) — используйте < id.
🔹Дата/время — удобно, но в редких случаях возможны совпадения секунд. Можно добавить второй критерий:
WHERE (created_at < :cursor_date)
OR (created_at = :cursor_date AND id < :cursor_id)
4️⃣ Советы и грабли ⚠️
🔹Создайте индекс (created_at DESC) или (created_at, id) — иначе даже key-set будет сканировать всю таблицу.
🔹Никогда не показывайте номер страницы пользователю, если используете key-set: курсор — это дата/ID, а не «страница 5».
🔹Для поиска по разным фильтрам (например, user_id) добавляйте их в индекс (user_id, created_at).
✅ Итог
🔹LIMIT + OFFSET подходит для админ-таблиц или маленьких данных.
🔹Для «бесконечных» лент используйте key-set pagination: быстрее, без дубликатов, идеально для мобильных фидов в духе Instagram/ТикТок.
Потренируйтесь: создайте таблицу posts, сгенерируйте 100 000 строк, сравните скорость OFFSET 90000 и key-set. Результат удивит! 🚀
SELECT name, is_vip
FROM customers
ORDER BY
CASE WHEN is_vip = 1 THEN 0 ELSE 1 END,
name;
-- внутри групп сортируем по алфавиту
▶️ CASE возвращает 0 для VIP, 1 — для всех остальных.
▶️ В порядке сортировки 0 идёт раньше 1, поэтому VIP‑ы будут первыми
🔹Сложнее: приоритеты A > B > C → остальные
SELECT name, status
FROM orders
ORDER BY CASE status
WHEN 'A' THEN 0
WHEN 'B' THEN 1
WHEN 'C' THEN 2
ELSE 3
END,
created_at DESC;
▶️ Сначала все со статусом A, потом B, затем C, затем остальные.
▶️ Внутри каждой группы — свежие заказы выше (по дате).
Типичные ошибки ⚠️
1️⃣ NULL‑ы: если столбец может быть NULL, добавьте явную проверку
CASE WHEN col IS NULL THEN …
2️⃣ Числа вместо строк: не забывайте, что CASE должен возвращать однотипные значения (в примерах — всегда INT).
3️⃣ Производительность: выражение в ORDER BY отключает использование индекса.
Для больших таблиц можно создать сгенерированный столбец с тем же CASE и проиндексировать его.
ALTER TABLE customers
ADD vip_sort TINYINT AS (CASE WHEN is_vip = 1 THEN 0 ELSE 1 END) STORED,
ADD INDEX (vip_sort);
Итоги ✅
🔸CASE в ORDER BY даёт гибкую условную сортировку без подзапросов.
🔸Легко расставить приоритеты: VIP, скидки, статусы…
🔸Следите за NULL‑ами и индексацией при больших объёмах.
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100)
);
🔹 Как задать стартовое значение
Нужно указать AUTO_INCREMENT = n при создании или изменить уже существующую таблицу:
-- сразу при создании
CREATE TABLE orders (
id INT AUTO_INCREMENT PRIMARY KEY,
product VARCHAR(100)
) AUTO_INCREMENT = 1000;
-- позднее
ALTER TABLE orders AUTO_INCREMENT = 5000;
💡 Полезно, если хотите «красивые» ID или переносите старые данные.
🔹 Почему появляются «дырки» в нумерации
1. DELETE. Удалили строку с id = 5 → число 5 уже не вернётся.
2. ROLLBACK. Транзакция вставила id = 6 и откатилась — 6 пропадает.
3. Сбой сервера. MySQL резервирует диапазон ID в буфере; при крэше часть чисел «теряется».
🔹 Можно ли сбросить счётчик?
Да, но осторожно.
ALTER TABLE users AUTO_INCREMENT = 1;
Условие: новое значение должно быть больше любого существующего id. Иначе получите ошибку или конфликт PK.
🛑 На проде почти никогда не делают — потеря сквозной уникальности мешает логам и внешним ссылкам.
🔹 Грабли и советы
1️⃣ Не используйте AUTO_INCREMENT как «количество строк» — после DELETE счётчик не отражает реальное число записей.
2️⃣ Храните ссылки на записи только по уникальным id, а не позициям.
3️⃣ Если важно отсутствие дырок (к примеру, номера чеков) — создавайте отдельную таблицу «генератор последовательностей» или используйте сериализацию в приложении.
📝 Итог
1️⃣ Начать с нужного числа — AUTO_INCREMENT = N.
2️⃣ Сбросить можно, но не ниже текущего максимума.
3️⃣ Пропуски после DELETE и ROLLBACK — нормальное поведение.
CREATE TABLE users (
id INT PRIMARY KEY,
age INT,
CHECK (age >= 0 AND age <= 120)
);
Теперь нельзя вставить пользователя с возрастом -5 или 999 — MySQL просто не даст это сделать.
Синтаксис CHECK
🔸 Можно добавлять при создании таблицы (CREATE TABLE) или позже (ALTER TABLE).
🔸 Можно использовать AND, OR, арифметику, сравнения, функции (с ограничениями).
🔸 Поддерживается в MySQL 8.0+. В старых версиях CHECK игнорировался (!).
Пример с условием на строку:
CREATE TABLE products (
id INT PRIMARY KEY,
name VARCHAR(100),
category ENUM('book', 'game', 'toy'),
price DECIMAL(10,2),
CHECK (price >= 0)
);
Здесь мы запрещаем отрицательные цены.
Добавление ограничения в существующую таблицу:
ALTER TABLE users
ADD CONSTRAINT chk_age CHECK (age >= 0 AND age <= 120);
Что произойдёт при нарушении?
INSERT INTO users (id, age) VALUES (1, -10);
-- ERROR 3819 (HY000): Check constraint 'chk_age' is violated.
⚠️ Важно помнить:
🔹CHECK срабатывает только для новых данных — старые строки не проверяются.
🔹Если значение NULL, правило обычно не нарушается (NULL считается «неизвестным» и не сравнивается напрямую).
🔹Ошибку можно перехватывать в приложении, чтобы сообщить пользователю.
✅ Когда стоит использовать CHECK:
🔹 Для ограничений: возраст, положительная цена, длина строки, формат (через LIKE или REGEXP).
🔹Когда хотите, чтобы в таблице «по умолчанию» всегда были только корректные данные.
🔹Чтобы упростить валидацию и сделать БД самодостаточной (например, при работе с внешними источниками данных).= NULL всегда возвращает FALSE → условия «теряют» строки.
🔹Агрегаты (`SUM`, `AVG`) игнорируют NULL → итоги оказываются заниженными.
🔹Деление на 0 вызывает ошибку, если предварительно не обработать значение.
В MySQL есть три базовые функции, которые помогают держать ситуацию под контролем.
1️⃣ IFNULL(expr, alt) — поставить значение по умолчанию
Возвращает alt, если expr равно NULL, иначе возвращает expr.
SELECT name,
IFNULL(email, 'no-email@example.com') AS contact
FROM users;
Результат: вместо NULL-email выводится строка-заглушка.
2️⃣ COALESCE(expr1, expr2, …) — взять первое ненулевое
Последовательно проверяет аргументы слева направо и возвращает первый, который не NULL.
SELECT name,
COALESCE(email, phone, 'нет контактов') AS main_contact
FROM users;
Сценарий: если email отсутствует, берём phone; если и он NULL — выводим фразу «нет контактов».
3️⃣ NULLIF(a, b) — обнулить при равенстве
Возвращает NULL, когда a = b, иначе возвращает a. Полезно, чтобы избежать деления на ноль.
SELECT revenue / NULLIF(orders_count, 0) AS avg_check
FROM shop_stats;
Если orders_count равен 0, деление не выполняется — результатом будет NULL вместо ошибки.
Памятка
🔹Для проверок используйте IS NULL и IS NOT NULL, а не = NULL.
🔹Проверяйте, как агрегатные функции ведут себя с пропущенными данными.
🔹В формулах страхуйтесь NULLIF, чтобы не получить «division by zero».
Запомните IFNULL, COALESCE и NULLIF — с ними работа с NULL становится предсказуемой и безопасной. 🚀
INSERT INTO messages (sent_at)
VALUES (UTC_TIMESTAMP());
✅ Читаем данные и переводим в нужный пояс (например, для Москвы, +03:00)
SELECT sent_at,
CONVERT_TZ(sent_at, '+00:00', '+03:00') AS sent_at_moscow
FROM messages;
🔹 Итоговые рекомендации:
1️⃣ Используйте TIMESTAMP для автоматического хранения данных в UTC.
2️⃣ Для ручного управления используйте тип DATETIME и всегда сохраняйте в UTC.
3️⃣ Переводите данные в локальное время только при отображении.
CREATE TABLE user_avatars (
id INT AUTO_INCREMENT PRIMARY KEY,
user_id INT NOT NULL,
avatar MEDIUMBLOB NOT NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
🔹 Вставка данных:
INSERT INTO user_avatars (user_id, avatar)
VALUES (123, LOAD_FILE('/path/to/avatar.png'));
Или передача через параметризованный запрос из приложения (PHP/Python), где двоичные данные вставляются напрямую.
🔹 Ограничения и подводные камни:
1️⃣ Большие BLOB замедляют запросы и увеличивают размер бэкапа
2️⃣ Нужны корректные настройки (max_allowed_packet, innodb_log_file_size и др.)
3️⃣ При блокировке таблицы с большим BLOB транзакции могут зависать дольше
4️⃣ Бэкапы и восстановление займут больше времени
🔹 Рекомендации:
1️⃣ Для больших файлов — отдельное хранилище (например, S3), а в БД только ссылки
2️⃣ При использовании BLOB — ограничивать максимальный размер файлов
3️⃣ Следить за правами (функция LOAD_FILE требует соответствующих привилегий)
4️⃣ Использовать кэширование (CDN), если часто выгружаете большие файлы
اکنون در دسترس! پژوهش تلگرام ۲۰۲۵ — مهمترین بینشهای سال 
