SQL Ready | Базы Данных
15.4K subscribers
1.2K photos
65 videos
2 files
577 links
Авторский канал про Базы Данных и SQL
Ресурсы, гайды, задачи, шпаргалки.
Информация ежедневно пополняется!

Автор: @energy_it

РКН: https://clck.ru/3QREBc

Реклама на бирже: https://telega.in/c/sql_ready
Download Telegram
📂 Напоминалка по шардингу баз данных!

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

На картинке — основные принципы шардинга баз данных, которые стоит держать под рукой.

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

➡️ SQL Ready | #ресурс
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥1610🤝8
ORDER BY в подзапросах: почему порядок не гарантируется!

ORDER BY управляет порядком строк только в финальном результате запроса. В подзапросах и CTE он не гарантирует порядок строк, если не используется вместе с ограничением количества возвращаемых данных.

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

Таблица событий:
events(id, user_id, created_at)


Попытка взять последние события через подзапрос:
SELECT *
FROM (
SELECT *
FROM events
ORDER BY created_at DESC
) t;


Несмотря на явный ORDER BY внутри подзапроса, внешний запрос не содержит сортировки.

Это означает, что порядок строк на выходе не определён, и СУБД имеет право проигнорировать внутреннюю сортировку как не влияющую на результат.

Корректный вариант — сортировать во внешнем запросе:
SELECT *
FROM events
ORDER BY created_at DESC;


Именно этот ORDER BY гарантирует порядок строк, который получит клиент или приложение.

Когда ORDER BY в подзапросе имеет смысл — он становится значимым только вместе с ограничением:
SELECT *
FROM (
SELECT *
FROM events
ORDER BY created_at DESC
LIMIT 10
) t
ORDER BY created_at DESC;


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

Внутренний ORDER BY определяет, какие именно 10 строк попадут в подзапрос, а внешний ORDER BY задаёт порядок финального результата.

Аналогичный принцип работает с оконными функциями:
SELECT id, user_id, created_at
FROM (
SELECT
id,
user_id,
created_at,
ROW_NUMBER() OVER (
PARTITION BY user_id
ORDER BY created_at DESC
) AS rn
FROM events
) s
WHERE rn = 1;


Здесь ORDER BY влияет на вычисление ROW_NUMBER, то есть на логику нумерации строк внутри окна, но не определяет порядок вывода строк в результирующем наборе.

🔥 ORDER BY — это про порядок выдачи результата, а не про порядок хранения данных. Без внешнего ORDER BY СУБД не обязана возвращать строки в каком-либо определённом порядке.

➡️ SQL Ready | #практика
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥1613👍12
😎 На Хабре вышла полезнейшая статья про репликацию в 1С и реальные нагрузки на СУБД!

В этой статье:
• Разбирается, как вынести тяжёлые отчёты 1С с мастер-базы на реплику;
• Показывается настройка репликации PostgreSQL/Tantor DB под реальные сценарии 1С;
• Анализируются узкие места, задержки репликации и влияние отчётных запросов;
• Даются результаты нагрузочного тестирования и выводы, которые можно применить в системах.


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


➡️ SQL Ready | #статья
Please open Telegram to view this post
VIEW IN TELEGRAM
👍139🔥8😁1
👍10🔥6🤝6👎1
Что же выведет консоль?
Anonymous Quiz
28%
A
27%
B
19%
C
26%
D
👍14🔥11🤝9👎1
Одна таблица играет сразу несколько ролей?

Иногда данные уже есть в одной таблице, но логически это разные сущности.

Классический пример, иерархия: сотрудник и его менеджер хранятся
в одной таблице employees:
FROM employees e
JOIN employees m


e — это сотрудник, m — это менеджер.

Физически это одна и та же таблица, но логически, разные роли:
ON m.id = e.manager_id


Связь читается так, у сотрудника есть manager_id, который указывает на id другого сотрудника.

🔥 Такой приём используется не только для менеджеров. Категории и родительские категории, комментарии и ответы, версии сущностей, связи предыдущий / следующий, графы, цепочки состояний и др.

➡️ SQL Ready | #совет
Please open Telegram to view this post
VIEW IN TELEGRAM
13👍13🤝8
🖥 Oracle: условная логика и выбор значений!

Разбор типовых приёмов классификации данных, обработки NULL, подстановки значений по условиям и вычисления итоговых результатов прямо в запросах. Полезно для отчётов, аналитики, бизнес-логики в SELECT, упрощения WHERE и ORDER BY, а также для написания компактного и читаемого SQL без изменения схемы БД.

➡️ SQL Ready | #шпора
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
14🤝14👍12
This media is not supported in your browser
VIEW IN TELEGRAM
👍 SQL Bootcamp — структурированная практика с упором на реальные задачи!

Этот репозиторий построен как полноценный тренажёр: реальные схемы данных, последовательные задания и разборы запросов разной сложности. Помогает системно разобраться в работе с базами данных: выборки, сложные JOIN, агрегации, подзапросы, фильтрация, изменение данных и др.

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


➡️ SQL Ready | #репозиторий
Please open Telegram to view this post
VIEW IN TELEGRAM
👍15🤝97
NTILE — разбиение данных на равные группы внутри партиций!

Оконные функции полезны не только для топов и агрегатов. Частый аналитический кейс — разложить данные по корзинам одинакового размера: квартилям, децилям, сегментам.

Представим таблицу:
users(id, country, revenue)


Нужно разбить пользователей каждой страны на 4 группы по выручке — от меньшей к большей.

Решение через NTILE:
SELECT
    id,
    country,
    revenue,
    NTILE(4) OVER (
        PARTITION BY country
        ORDER BY revenue
    ) AS revenue_quartile
FROM users;


NTILE(4) распределяет строки внутри каждой партиции на 4 группы максимально равного размера.
ORDER BY определяет, какие значения попадут в «нижние» и «верхние» группы.

Результат: quartile = 1 — пользователи с минимальной выручкой, quartile = 4 — пользователи с максимальной выручкой

Важно: группы не всегда будут строго одинаковыми по размеру. Если строк не делится нацело, первые группы получат на одну строку больше.

Если убрать PARTITION BY:
NTILE(4) OVER (ORDER BY revenue)


Разбиение произойдёт по всей таблице, без учёта страны.

Практический кейс — сегментация:
SELECT *
FROM (
    SELECT
        *,
        NTILE(10) OVER (
            PARTITION BY country
            ORDER BY revenue DESC
        ) AS decile
    FROM users
) t
WHERE decile = 1;


Так можно выбрать топ-10% пользователей в каждой стране.

NTILE работает построчно и не агрегирует данные — каждая строка сохраняется, а группа добавляется как аналитическая метка.

🔥 Используйте NTILE, когда нужно сегментировать данные внутри группы на равные части без предварительной агрегации.

➡️ SQL Ready | #практика
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1411🔥8🤝2
This media is not supported in your browser
VIEW IN TELEGRAM
😎 Kaggle Learn — короткие практические модули с упражнениями и датасетами!

Серия коротких и чётких микро-курсов с упором на практику: каждый модуль - это конкретная тема, упражнения и работа с настоящими датасетами прямо в браузере. Подходит для быстрого освоения основ языка, закрепления синтаксиса и понимания, как Python используется в реальных задачах.

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

➡️ SQL Ready | #сайт
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥15👍9🤝8
Постоянные представления, как слой архитектуры!

VIEW — сохранённый запрос, как объект схемы. Для обычных VIEW данные не дублируются: оптимизатор, как правило, раскрывает их в подзапрос и строит единый план (зависит от СУБД):
SELECT *
FROM active_users
WHERE email LIKE '%@company.com';


Логика фильтрации находится в одном месте, без копирования условий по коду.
CREATE OR REPLACE VIEW active_users AS
SELECT id, name, email
FROM users
WHERE deleted_at IS NULL
AND NOT is_blocked;


CREATE OR REPLACE позволяет централизованно менять логику (если сохраняется совместимый контракт колонок), не переписывая клиентские запросы:
GRANT SELECT ON active_users TO reporting_role;


🔥 Права можно выдавать на VIEW, а не на таблицу, скрывая лишние поля и фиксируя допустимую проекцию (механика зависит от СУБД).

➡️ SQL Ready | #совет
Please open Telegram to view this post
VIEW IN TELEGRAM
13🔥13👍9🤝2
This media is not supported in your browser
VIEW IN TELEGRAM
☕️ Introduction to SQL — открытая книга по SQL, краткое и практичное руководство!

Это полноценный бесплатный ресурс в формате репозитория, который даёт основу работы с реляционными базами данных. Здесь структура БД, таблицы, SELECT, JOIN, подзапросы, агрегаты, изменение данных и экспорт баз. Материал ориентирован на реальные задачи DevOps, backend-разработки и системного администрирования.

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


➡️ SQL Ready | #репозиторий
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥15👍87🤝4
Индекс для поиска по шаблону, который действительно работает!

Обычные B-tree индексы хорошо работают только для шаблонов вида prefix%. Но при поиске по подстроке (%text%) или сложных шаблонах они обычно не используются, и запрос превращается в полный скан таблицы даже на миллионах строк.
CREATE EXTENSION IF NOT EXISTS pg_trgm;


Расширение pg_trgm добавляет триграммные индексы, которые эффективно ищут подстроки, частичные совпадения и нечёткие шаблоны:
CREATE INDEX users_email_trgm_idx
ON users USING gin (email gin_trgm_ops);


После этого запросы вроде:
SELECT *
FROM users
WHERE email ILIKE '%company%';


Начинают использовать индекс и ускоряются, особенно для поиска по почте, логинам, URL и другим текстовым идентификаторам:
EXPLAIN ANALYZE
SELECT *
FROM users
WHERE email ILIKE '%company%';


🔥 Важно: триграммный индекс занимает больше места и замедляет INSERT/UPDATE, но для больших таблиц с поиском по подстроке это почти всегда оправдано.

➡️ SQL Ready | #совет
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥1411👍9
📂 Напоминалка как выполняется SQL-запрос в реляционной СУБД!

Например, Transport Subsystem — приём запроса от клиента по сетевому протоколу, установка сессии, а Query Processor — синтаксический и семантический разбор, построение дерева запроса (parse tree).

На схеме показан полный путь запроса — от клиента до хранения данных.

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

➡️ SQL Ready | #ресурс
Please open Telegram to view this post
VIEW IN TELEGRAM
15👍9🔥8🤝3
Оконные агрегаты, как считать по группе и не терять строки!

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

Представим таблицу заказов:
orders(id, customer_id, amount, created_at)


Хотим увидеть все заказы и одновременно понимать, сколько денег каждый клиент потратил в сумме.

Первая мысль — посчитать через GROUP BY:
SELECT
customer_id,
SUM(amount) AS total_amount
FROM orders
GROUP BY customer_id;


Да, сумму он посчитает. Но список заказов пропадёт — останется по одной строке на клиента.

Если коротко: GROUP BY считает по группе, но детали внутри группы выбрасывает.

Решение через оконную функцию:
SELECT
id,
customer_id,
amount,
SUM(amount) OVER (PARTITION BY customer_id) AS total_amount
FROM orders;


PARTITION BY customer_id разбивает строки на независимые окна по клиентам.
SUM(...) OVER (...) считает сумму внутри каждого окна, но строки не схлопывает — каждая остаётся на месте.

В результате каждая строка — отдельный заказ и total_amount — сумма всех заказов этого клиента.

Фильтрация по агрегату без GROUP BY — например, нужно выбрать только заказы тех клиентов, у которых суммарный оборот больше 1000:
SELECT *
FROM (
SELECT
*,
SUM(amount) OVER (PARTITION BY customer_id) AS total_amount
FROM orders
) t
WHERE total_amount > 1000;


Обратите внимание: фильтрация происходит уже после вычисления оконной функции. Никаких GROUP BY, никаких дополнительных JOIN.

Та же логика через JOIN (для сравнения):
SELECT o.*
FROM orders o
JOIN (
SELECT customer_id, SUM(amount) AS total_amount
FROM orders
GROUP BY customer_id
) s ON s.customer_id = o.customer_id
WHERE s.total_amount > 1000;


Работает, но выглядит тяжелее: отдельный подзапрос, джойн, дублирование таблицы.

Можно посчитать сразу несколько агрегатов по тем же окнам:
SELECT
id,
customer_id,
amount,
SUM(amount) OVER (PARTITION BY customer_id) AS total_amount,
COUNT(*) OVER (PARTITION BY customer_id) AS orders_count
FROM orders;


Получаем и общую сумму, и количество заказов клиента — прямо в каждой строке.

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

➡️ SQL Ready | #практика
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1813🔥8
This media is not supported in your browser
VIEW IN TELEGRAM
👍 TutorialsPoint — сайт с теорий и практикой в одном месте!

Удобный онлайн-редактор, где можно быстро проверить SQL-запросы без установки СУБД и настройки окружения. Встроенные примеры позволяют сразу попробовать SELECT, JOIN, агрегатные функции, подзапросы и другие конструкции на готовых таблицах. Подходит для обучения, практики, подготовки к собесам. Также можно использовать, как мини шпаргалку.

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

➡️ SQL Ready | #сайт
Please open Telegram to view this post
VIEW IN TELEGRAM
15👍9🔥7🤝2