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

Cотрудничество: @energy_c

РКН: https://clck.ru/3QREBc
Download Telegram
🖥 PostgreSQL — блокировки строк и конкурентный доступ!

Шпаргалка по механизмам синхронизации параллельных транзакций в PostgreSQL: защита строк от конкурентных изменений и удаления, управление ожиданием и пропуском занятых строк, явная блокировка таблиц и диагностика ожидающих блокировок. Помогает контролировать конкурентный доступ и корректно реализовывать транзакционные сценарии.

➡️ SQL Ready | #шпора
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
13👍10🔥8
📂 Шпаргалка по нормализации баз данных в MySQL!

Например, 1NF требует атомарных значений, 2NF избавляет от частичных зависимостей, а 3NF — от транзитивных. Для более сложных схем пригодятся BCNF и 4NF.

На картинке — основные нормальные формы с требованиями, примерами и пользой каждой из них.

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

➡️ SQL Ready | #ресурс
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥1710🤝8👎1
❤️ Интересная статья на Хабре: «Что такое RAGFlow и с чем его едят»!

В этой статье:
• Разберётесь, как RAGFlow помогает LLM работать с внутренними документами и снижать количество галлюцинаций;
• Узнаете, чем RAGFlow отличается от классического RAG и как он обрабатывает PDF, таблицы, схемы и сканы;
• Посмотрите, как развернуть RAGFlow и использовать его для баз знаний, техподдержки и аналитики.

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


➡️ SQL Ready | #статья
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥11👍6🤝5
🔥14🤝7👍4
UNIQUE и NULL в PostgreSQL 15!

До PostgreSQL 15 уникальные ограничения считали NULL разными значениями. Это означало, что таблица спокойно принимала сколько угодно строк с NULL, даже если на колонке стоял UNIQUE.
CREATE TABLE users (
email text UNIQUE
);

INSERT INTO users VALUES (NULL);
INSERT INTO users VALUES (NULL);


Обе вставки выполнятся успешно.

Если NULL тоже должен быть уникальным, приходилось придумывать обходные пути. Кто-то делал частичные индексы, кто-то использовал COALESCE(), кто-то заводил отдельные флаги.
CREATE TABLE users (
email text,
CONSTRAINT users_email_key
UNIQUE NULLS NOT DISTINCT (email)
);

INSERT INTO users VALUES (NULL);
INSERT INTO users VALUES (NULL);


Вторая вставка уже завершится ошибкой. Для ограничения NULL считается таким же значением, как и любой другой ключ.
CREATE TABLE users (
tenant_id int,
email text,
CONSTRAINT uq_user
UNIQUE NULLS NOT DISTINCT (tenant_id, email)
);


Полезно, когда NULL — это полноценное значение предметной области, а не просто "неизвестно".

🔥 Небольшая возможность PostgreSQL 15, которая позволяет удалить сразу несколько старых костылей вокруг UNIQUE.

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

Сайт для тех, кто хочет освоить SQL через работу с запросами. Код пишется прямо в браузере: выполняете запрос, сразу видите результат и получаете автоматическую проверку решения. Обучение построено от базовых SELECT и ORDER BY до JOIN, подзапросов, транзакций, индексов, оптимизации запросов и PostgreSQL. Есть структурированные курсы с теорией и практикой.

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

➡️ SQL Ready | #ресурс
Please open Telegram to view this post
VIEW IN TELEGRAM
12👍11🔥5
Научите оптимизатор понимать ваши данные!

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

Например, если city = 'Paris', то country почти всегда будет 'France'. Без этой информации оптимизатор может сильно ошибиться при оценке количества строк и выбрать неудачный план.
EXPLAIN
SELECT *
FROM users
WHERE country = 'France'
AND city = 'Paris';


Вместо того чтобы сразу создавать новый индекс, попробуйте расширенную статистику.
CREATE STATISTICS users_dep (dependencies)
ON country, city
FROM users;

ANALYZE users;


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

🔥 Если запрос фильтрует по нескольким связанным колонкам и оптимизатор ошибается в оценке, сначала попробуйте CREATE STATISTICS, а уже потом решайте, нужен ли новый индекс.

➡️ SQL Ready | #совет
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥1610👍7
📂 Шпаргалка по Backend-разработке!

Например, REST используется для построения API, Redis помогает кэшировать данные, а Docker позволяет упаковать приложение вместе со всеми его зависимостями.

На картинке — основные направления Backend-разработки: языки программирования, базы данных, API, авторизация, серверы, контейнеризация, CI/CD и мониторинг. Полезная карта того, что стоит изучить Backend-разработчику.

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

➡️ SQL Ready | #ресурс
Please open Telegram to view this post
VIEW IN TELEGRAM
13🔥7👍5
Почему коррелированные подзапросы могут снижать производительность SQL-запроса!

Коррелированные подзапросы удобны: внутри них можно обращаться к значениям текущей строки внешнего запроса.

Проблема в том, что оптимизатор может выбрать план, при котором такой подзапрос будет выполняться повторно для каждой строки внешней выборки. На больших объёмах данных это может стать узким местом. Например:
SELECT
u.id,
u.name,
(
SELECT SUM(o.amount)
FROM orders o
WHERE o.user_id = u.id
) AS total_amount
FROM users u;


Если users содержит миллион строк, подзапрос потенциально может быть выполнен миллион раз. Даже при наличии индекса по orders.user_id такой подход иногда становится менее эффективным, особенно в сложных отчётах.

Часто можно сначала агрегировать данные, а затем присоединить результат:
SELECT
u.id,
u.name,
COALESCE(o.total_amount, 0) AS total_amount
FROM users u
LEFT JOIN (
SELECT
user_id,
SUM(amount) AS total_amount
FROM orders
GROUP BY user_id
) o
ON o.user_id = u.id;


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

Но это не универсальное правило. Современные оптимизаторы умеют преобразовывать некоторые коррелированные подзапросы в более эффективные планы выполнения, поэтому всегда нужно смотреть реальный план через EXPLAIN / EXPLAIN ANALYZE.

Для получения последнего заказа пользователя часто используют оконные функции:
SELECT
user_id,
created_at
FROM (
SELECT
user_id,
created_at,
ROW_NUMBER() OVER (
PARTITION BY user_id
ORDER BY created_at DESC
) AS rn
FROM orders
) t
WHERE rn = 1;


Но и здесь нет универсального решения. При правильном индексе, например:
(user_id, created_at DESC)


коррелированный запрос вида:
SELECT ...
FROM orders
WHERE user_id = ?
ORDER BY created_at DESC
LIMIT 1;


может быть быстрее, потому что база сможет быстро найти одну нужную строку через индекс.

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

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

➡️ SQL Ready | #практика
Please open Telegram to view this post
VIEW IN TELEGRAM
15👍7🔥4🤝3
This media is not supported in your browser
VIEW IN TELEGRAM
✍️ Архитектура высоконагруженных систем — подробный материал по проектированию Highload!

Здесь разобраны ключевые вещи, с которыми сталкиваются при разработке нагруженных систем: RPS, latency и throughput, вертикальное и горизонтальное масштабирование, индексы, репликация и шардирование баз данных, кеширование, брокеры сообщений и др. Есть практические примеры с MySQL, PostgreSQL, Kafka и Tarantool, а также инструменты для тестирования и мониторинга.

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


➡️ SQL Ready | #репозиторий
Please open Telegram to view this post
VIEW IN TELEGRAM
👍125🔥5🤝3
🐱 Нашел крайне занимательную статью на Хабре: «Условная агрегация в SQL: ускоряем отчеты, избавляясь от лишних JOIN-ов и подзапросов»!

В этой статье:
• Узнаете, как ускорять сложные SQL-запросы с помощью условной агрегации;
• Разберёте применение CASE и FILTER вместо множества подзапросов и JOIN-ов;
• Посмотрите на примерах, как сделать SQL-код быстрее, чище и проще для поддержки.

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


➡️ SQL Ready | #статья
Please open Telegram to view this post
VIEW IN TELEGRAM
👍126🔥6🤝2
7,2 млн рублей призового фонда и реальные задачи космической отрасли 🚀

В сентябре пройдет серия КосмоХакатонов для студентов, молодых ученых и специалистов.
Участникам предстоит за два дня разработать собственное решение, поработать с экспертами и представить проект жюри.

Участников ждут:
🛰 реальные задачи космической отрасли
👥 команды от 3 до 5 человек
💻 очный и онлайн-форматы
🧑‍💻 работа с экспертами и трекерами
🏆 финал в Москве

Первый КосмоХакатон стартует уже 4 сентября в Ростове-на-Дону.

Дальше серия продолжится в Красноярске, Нижнем Новгороде, Благовещенске и Санкт-Петербурге, а завершится финалом в Москве.

Участие бесплатное. Присоединиться могут студенты, аспиранты, молодые ученые и специалисты от 18 лет.
🔗 Зарегистрироваться: https://космохакатон.рф
Почему ctid нельзя использовать как постоянный идентификатор!

В PostgreSQL каждая строка имеет системную колонку ctid. Она содержит физический адрес текущей версии строки в таблице: номер страницы и позицию строки внутри этой страницы.

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

Для начала создадим простую таблицу с первичным ключом и несколькими тестовыми записями, чтобы наглядно проследить, как изменяется значение ctid.
CREATE TABLE users (
id INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
name TEXT
);


Теперь добавим несколько строк, с которыми будем работать в дальнейших примерах.
INSERT INTO users (name)
VALUES
('Alice'),
('Bob'),
('Charlie');


Посмотрим, какое значение ctid PostgreSQL присвоил каждой записи после вставки.
SELECT
ctid,
id,
name
FROM users;


Результат может выглядеть так:
ctid  | id | name
------+----+--------
(0,1) | 1 | Alice
(0,2) | 2 | Bob
(0,3) | 3 | Charlie


Теперь изменим одну из строк. На первый взгляд кажется, что PostgreSQL просто обновит существующую запись, однако механизм хранения данных работает иначе.
UPDATE users
SET name = 'Robert'
WHERE id = 2;


После выполнения UPDATE снова посмотрим значения ctid и сравним их с предыдущим результатом.
SELECT
ctid,
id,
name
FROM users;


Теперь можно увидеть, что значение ctid изменилось. Например:
ctid  | id | name
------+----+---------
(0,1) | 1 | Alice
(0,4) | 2 | Robert
(0,3) | 3 | Charlie


Это происходит из-за механизма MVCC. При выполнении UPDATE PostgreSQL не изменяет строку на месте, а создаёт её новую версию, которая получает новый физический адрес (ctid). Старая версия строки некоторое время остаётся в таблице и может быть видима другим транзакциям в зависимости от их снимка данных.

Изменение ctid происходит не только при UPDATE. Любые операции, которые физически переписывают таблицу, также приводят к изменению физических адресов строк. Например:
VACUUM FULL users;


или
CLUSTER users USING users_pkey;


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

Например, создадим отдельную таблицу без ограничений уникальности:
CREATE TABLE duplicate_users (
name TEXT
);


Добавим одинаковые строки:
INSERT INTO duplicate_users (name)
VALUES
('Alice'),
('Alice'),
('Bob');


Удалим только одну из двух одинаковых строк:
DELETE
FROM duplicate_users
WHERE ctid = (
SELECT ctid
FROM duplicate_users
WHERE name = 'Alice'
LIMIT 1
);


В результате останется одна строка с именем Alice. В этом примере ctid определяется и используется в рамках одного SQL-запроса, поэтому используется актуальный физический адрес версии строки и не возникает проблемы с использованием устаревшего значения.

🔥 ctid — это физический адрес текущей версии строки, а не её постоянный идентификатор. Для связи данных всегда используйте первичный ключ, а ctid оставьте для диагностических и служебных операций.

➡️ SQL Ready | #практика
Please open Telegram to view this post
VIEW IN TELEGRAM
👍136🔥5
🖥 MySQL — работа с NULL!

Шпаргалка по обработке NULL в MySQL: подстановка резервных значений, проверка наличия и отсутствия данных, условная обработка, безопасные вычисления и сравнение nullable-значений. Помогает учитывать семантику NULL и избегать неочевидного поведения в условиях, выражениях и вычислениях.

➡️ SQL Ready | #шпора
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
13🔥7👍5😁2
This media is not supported in your browser
VIEW IN TELEGRAM
😍 zasqlpython — платформа для изучения и практики SQL!

Сайт позволяет изучать SQL с нуля и сразу закреплять материал на практике. Бесплатный курс включает 10 уроков и 92 задачи с автоматической проверкой прямо в браузере. После базового курса можно перейти к SQL-тренажёру с сотнями задач повышенной сложности и заданиями в формате собеседований.

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

➡️ SQL Ready | #ресурс
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥138🤝5