7786
Авторский канал про Базы Данных и SQL Ресурсы, гайды, задачи, шпаргалки. Информация ежедневно пополняется! Автор: @energy_it
Обновляйте несколько колонок одним подзапросом!
Вместо нескольких одинаковых подзапросов:
UPDATE orders o
SET customer_name = (
SELECT name FROM customers WHERE id = o.customer_id
),
customer_email = (
SELECT email FROM customers WHERE id = o.customer_id
);
-- Один подзапрос сразу для нескольких колонок
UPDATE orders o
SET (customer_name, customer_email) = (
SELECT c.name, c.email
FROM customers c
WHERE c.id = o.customer_id
);
UPDATE accounts a
SET (last_payment_at, total_paid) = (
SELECT max(p.created_at),
sum(p.amount)
FROM payments p
WHERE p.account_id = a.id
);
SET (a, b, ...) = (SELECT ...) позволяет одним подзапросом вычислить сразу несколько новых значений строки и заметно сокращает повторяющийся SQL.
Почему UNIQUE допускает несколько NULL в PostgreSQL!
Ограничение UNIQUE гарантирует уникальность значений, но для NULL в PostgreSQL действует отдельная семантика. По умолчанию два NULL считаются различными при проверке уникальности, поэтому ограничение не запрещает несколько строк с неопределённым значением:
CREATE TABLE users (
id BIGINT PRIMARY KEY,
email TEXT UNIQUE
);
email нарушит ограничение уникальности.INSERT INTO users (id, email)
VALUES (1, 'user@example.com');
INSERT INTO users (id, email)
VALUES (2, 'user@example.com');
NULL те же правила не применяются: несколько строк успешно проходят проверку ограничения.INSERT INTO users (id, email)
VALUES
(3, NULL),
(4, NULL),
(5, NULL);
CREATE TABLE contacts (
id BIGINT PRIMARY KEY,
company_id BIGINT NOT NULL,
external_id TEXT,
UNIQUE (company_id, external_id)
);
(company_id, external_id) конфликтуют, но несколько комбинаций (10, NULL) по умолчанию допустимы:INSERT INTO contacts (id, company_id, external_id)
VALUES
(1, 10, NULL),
(2, 10, NULL);
NULLS NOT DISTINCT. В таком ограничении NULL считаются неразличимыми при проверке уникальности:CREATE TABLE contacts_strict (
id BIGINT PRIMARY KEY,
company_id BIGINT NOT NULL,
external_id TEXT,
UNIQUE NULLS NOT DISTINCT (company_id, external_id)
);
(10, NULL) нельзя: вторая вставка завершится нарушением уникальности.INSERT INTO contacts_strict (id, company_id, external_id)
VALUES (1, 10, NULL);
INSERT INTO contacts_strict (id, company_id, external_id)
VALUES (2, 10, NULL);
CREATE UNIQUE INDEX uq_contacts_company_external
ON contacts (company_id, external_id)
NULLS NOT DISTINCT;
NULLS NOT DISTINCT не эквивалентен NOT NULL. NOT NULL полностью запрещает отсутствие значения, тогда как NULLS NOT DISTINCT разрешает NULL, но включает его в контроль уникальности.CREATE TABLE identifiers (
id BIGINT PRIMARY KEY,
external_id TEXT,
UNIQUE NULLS NOT DISTINCT (external_id)
);
external_id IS NULL, но вторая аналогичная строка уже нарушит ограничение.UNIQUE в PostgreSQL по умолчанию допускает несколько NULL. Если отсутствие значения также должно быть уникальным состоянием, начиная с PostgreSQL 15 это можно явно зафиксировать через NULLS NOT DISTINCT.
Проверяйте связи с учётом периода!
В PostgreSQL 18 связь может учитывать ещё и период его действия.WITHOUT OVERLAPS не даст создать пересекающиеся периоды для одного product_id. По сути PostgreSQL сам обеспечивает проверку пересечения диапазонов.
А теперь интересная часть:
CREATE TABLE discounts (
product_id bigint,
valid_at daterange,
FOREIGN KEY (
product_id,
PERIOD valid_at
)
REFERENCES prices (
product_id,
PERIOD valid_at
)
);
INSERT INTO discounts
VALUES (
42,
'[2026-05-01,2026-05-15)'::daterange
);
PERIOD позволяет проверять временные связи обычным FOREIGN KEY — без триггеров и ручных проверок.
👍 Устройство PostgreSQL — подробная документация на русском языке!
Материалы посвящены не написанию SQL-запросов, а архитектуре СУБД и внутренним механизмам обработки и хранения данных. Подробно рассматриваются физическая структура базы данных, системные каталоги, управление транзакциями, блокировки, WAL и др.
📌 Оставляю ссылочку: database.diasoft.ru
➡️ SQL Ready | #ресурс
Проверяйте JSON без преобразования!
Если JSON приходит как text, необязательно делать ::jsonb и ловить ошибку преобразования. IS JSON просто вернёт true или false.
SELECT '{"id": 42}' IS JSON; -- true
SELECT '{broken}' IS JSON; -- falseJSON:SELECT payload IS JSON OBJECT
FROM staging;
SELECT payload IS JSON ARRAY
FROM staging;
SELECT '{"id":1,"id":2}'
IS JSON OBJECT WITH UNIQUE KEYS;
-- falseCREATE TABLE incoming_events (
payload text NOT NULL
CHECK (payload IS JSON OBJECT WITH UNIQUE KEYS)
);
IS JSON позволяет валидировать JSON как обычное условие SQL — без преобразований, исключений и регулярных выражений.
😍 SQL-Tutorial — бесплатный учебник по SQL с практическими заданиями!
Онлайн-учебник для изучения SQL: от базовых запросов до более сложной работы с данными. Теория сопровождается примерами и упражнениями, поэтому изученные конструкции можно сразу закреплять на практике. Материал разделён на главы, что удобно для поэтапного обучения.
📌 Оставляю ссылочку: sql-tutorial.ru
➡️ SQL Ready | #ресурс
📂 Шпаргалка по числовым функциям!
Например, ROUND() используется для округления значений, MOD() — для получения остатка от деления, а агрегатные функции AVG(), SUM(), MIN() и MAX() помогают выполнять вычисления по наборам данных.
На изображении собраны основные числовые функции: назначение, синтаксис, примеры запросов и особенности использования в разных СУБД.
Сохрани, чтобы не потерять!
➡️ SQL Ready | #ресурс
🖥 PostgreSQL — разделение и сборка строк!Объединение значений с CONCAT и CONCAT_WS, агрегация строк с STRING_AGG, извлечение отдельных частей с SPLIT_PART, преобразование строк в массивы и обратно с STRING_TO_ARRAY и ARRAY_TO_STRING, а также разделение данных по регулярным выражениям с REGEXP_SPLIT_TO_ARRAY и REGEXP_SPLIT_TO_TABLE. Полезно для обработки списков, тегов, адресов и других текстовых данных.
➡️ SQL Ready | #шпора
Пачку офферов заказывали?
О всех трудоустройствах через ИИ-ассистента Софи ребята узнают от пользователей.
И какой же кайф, когда они делятся своими историями.
Вот так в чате узнали сразу о трех новых офферах:
• Кейс Сергея - 2 недели в Софи и 2 оффера.
• Кейс Елены - 1 неделя в Софи и оффер спустя 10 лет перерыва в работе. Елене 52 года.
• Кейс Юлии - 1 месяц в Софи, свитчер из финансового аналитика в разработчика SQL. И еще один оффер🎉
Искренние поздравления ребятам и удачи им на новой работе!
Зайти на 3 бесплатных дня в Софи можно уже сейчас.
Регистрируйся здесь.
👨💻 SQL PostgreSQL Patterns Library — большая коллекция готовых SQL-решений для PostgreSQL!
Здесь собраны практические запросы для работы со строками, JSON и массивами, поиска и оптимизации, массового обновления данных, индексов, миграций и администрирования БД. Есть решения для реальных задач: от UPSERT и поиска дубликатов до EXPLAIN, работы с миллионами записей, мониторинга запросов и обслуживания PostgreSQL.
Оставляю ссылочку: GitHub 📱
Как атомарно резервировать лимит без SELECT FOR UPDATE!
При работе с квотами, остатками и лимитами важно не допустить, чтобы конкурентные запросы одновременно прошли проверку одного и того же доступного значения. Если проверка выполняется отдельно от изменения данных, между этими операциями появляется окно гонки:
SELECT used, quota
FROM accounts
WHERE id = 42;
used = 80 при quota = 100 и каждый собирается зарезервировать ещё 15, обе проверки в приложении могут успешно пройти. UPDATE accounts
SET used = used + 15
WHERE id = 42
AND used + 15 <= quota
RETURNING used;
UPDATE одной строки сериализуется через row-level locking. Если другая транзакция успела изменить строку, условие WHERE для ожидавшего UPDATE будет повторно проверено относительно актуальной версии строки в READ COMMITTED:UPDATE accounts
SET used = used + :amount
WHERE id = :account_id
AND used <= quota - :amount
RETURNING id, used, quota;
RETURNING, резервирование выполнено. Если результат пустой, строка отсутствует либо доступного лимита недостаточно. Для прикладной логики эти случаи при необходимости можно различить отдельной проверкой после неуспешной попытки.amount >= 0: это стоит валидировать в приложении или закрепить ограничением на уровне БД:UPDATE inventory
SET reserved = reserved + :qty
WHERE product_id = :product_id
AND reserved <= stock - :qty
RETURNING product_id, reserved;
SELECT FOR UPDATE здесь нужен не всегда: если проверку можно выразить непосредственно в WHERE, сам UPDATE становится точкой синхронизации:UPDATE limits
SET consumed = consumed + :delta
WHERE id = :id
AND consumed <= maximum - :delta
RETURNING consumed;
consumed + delta <= maximum над одной строкой лучше проверять внутри атомарного UPDATE, а не между SELECT и UPDATE в приложении. Это сокращает критическую секцию и корректно работает при конкурентном изменении строки.
Разворачивайте несколько массивов вместе!
Когда приложение передаёт несколько связанных массивов, не нужно отдельно делать unnest(), нумеровать элементы и потом соединять их по позиции.
SELECT *
FROM unnest(
ARRAY[101, 102, 103],
ARRAY['book', 'mouse', 'keyboard'],
ARRAY[2, 1, 4]
) AS x(id, name, qty);
101/book/2, 102/mouse/1, 103/keyboard/4.INSERT INTO order_items (product_id, quantity)
SELECT *
FROM unnest(
:product_ids::bigint[],
:quantities::integer[]
);
UPDATE products p
SET price = x.price
FROM unnest(
:ids::bigint[],
:prices::numeric[]
) AS x(id, price)
WHERE p.id = x.id;
unnest(array1, array2, ...) объединяет связанные массивы в строки и позволяет массово добавлять или обновлять данные одним запросом.
Почему порядок колонок в составном индексе важен!
Составной индекс часто создают, когда запрос фильтрует данные сразу по нескольким колонкам. Но просто добавить нужные поля в индекс недостаточно — их порядок влияет на то, какую часть индекса PostgreSQL сможет эффективно использовать.
Есть таблица:
CREATE TABLE orders (
id BIGINT,
user_id BIGINT,
status VARCHAR(20),
created_at TIMESTAMPTZ,
amount NUMERIC(12,2)
);
SELECT
id,
created_at,
amount
FROM orders
WHERE user_id = 1500
AND created_at >= TIMESTAMPTZ '2026-09-01 00:00:00+00'
ORDER BY created_at;
CREATE INDEX idx_orders_user_created
ON orders (user_id, created_at);
user_id:user_id = 1500
created_at задаёт диапазон уже внутри записей этого пользователя:created_at >= TIMESTAMPTZ '2026-09-01 00:00:00+00'
ORDER BY created_at: при фиксированном user_id PostgreSQL может получить строки из индекса уже в нужном порядке и при подходящем плане обойтись без отдельной сортировки.CREATE INDEX idx_orders_created_user
ON orders (created_at, user_id);
created_at >= TIMESTAMPTZ '2026-09-01 00:00:00+00'
user_id всё ещё может участвовать в индексном сканировании, но уже не сокращает начальный диапазон B-tree так же эффективно, как в варианте (user_id, created_at). Разница особенно заметна, если за выбранный период накопились миллионы заказов разных пользователей.(user_id, created_at) хорошо подходит и для запроса только по ведущей колонке:WHERE user_id = 1500;
WHERE user_id = 1500
AND created_at >= TIMESTAMPTZ '2026-09-01 00:00:00+00';
created_at обычно не получает от этого индекса того же преимущества, поскольку условие на ведущую колонку отсутствует:WHERE created_at >= TIMESTAMPTZ '2026-09-01 00:00:00+00';
EXPLAIN (ANALYZE, BUFFERS)
SELECT
id,
created_at,
amount
FROM orders
WHERE user_id = 1500
AND created_at >= TIMESTAMPTZ '2026-09-01 00:00:00+00'
ORDER BY created_at;
ANALYZE orders;). На маленькой или пустой таблице PostgreSQL вполне может выбрать Seq Scan, и это будет нормальным поведением оптимизатора.(a, b) особенно эффективен сценарий, когда сначала ограничивается ведущая колонка a, а затем используется диапазон по b. Если запрос содержит равенство и диапазон, колонку с равенством часто имеет смысл поставить перед колонкой с диапазоном. Но окончательный выбор индекса должен подтверждаться реальным execution plan.
Составные индексы: правила проектирования и типичные ошибки!
Составные индексы используются для ускорения запросов по нескольким колонкам, но порядок полей внутри индекса напрямую влияет на его эффективность.
Представим таблицу заказов, где часто выполняются запросы по пользователю и дате создания заказа.
CREATE TABLE orders (
id BIGSERIAL PRIMARY KEY,
user_id BIGINT NOT NULL,
status VARCHAR(30),
created_at TIMESTAMP NOT NULL,
amount NUMERIC(10,2)
);
CREATE INDEX idx_orders_user
ON orders(user_id);
CREATE INDEX idx_orders_created_at
ON orders(created_at);
CREATE INDEX idx_orders_user_created_at
ON orders(user_id, created_at);
SELECT *
FROM orders
WHERE user_id = 42
AND created_at >= '2026-01-01';
user_id, а внутри одинаковых значений user_id — по created_at.SELECT *
FROM orders
WHERE user_id = 42;
SELECT *
FROM orders
WHERE created_at >= '2026-01-01';
CREATE INDEX idx_orders_created_at
ON orders(created_at);
CREATE INDEX idx_orders_all_columns
ON orders(user_id, status, created_at, amount);
EXPLAIN ANALYZE
SELECT *
FROM orders
WHERE user_id = 42
AND status = 'paid'
ORDER BY created_at DESC;
CREATE INDEX idx_orders_user_status_created_at
ON orders(user_id, status, created_at DESC);
😍 PostgreSQL Zero to Hero — большой русскоязычный материал по изучению PostgreSQL!
Здесь разобраны основы SQL, проектирование баз данных, индексы, транзакции, MVCC, WAL, оптимизация запросов, репликация, бэкапы и многое другое. Подойдёт разработчикам, которые хотят системно изучить PostgreSQL и разобраться не только с SQL, но и с архитектурой, производительностью, эксплуатацией базы данных.
Оставляю ссылочку: GitHub 📱
❤️ sqlite-postgres-cours — большой практический курс по базам данных!
Материал ведёт от первых SQL-запросов и проектирования схем до индексов, транзакций, оптимизации и работы с БД из Python через SQLAlchemy и Alembic. Особенно полезно, что SQLite и PostgreSQL изучаются параллельно: автор показывает различия между ними, типичные ошибки и ситуации, где выбор СУБД имеет значение.
Оставляю ссылочку: GitHub 📱
📂 Шпаргалка по паттернам распределённых систем!
Например, Replication повышает доступность и отказоустойчивость за счёт хранения копий данных на нескольких узлах, а Sharding позволяет горизонтально масштабировать систему, распределяя данные между независимыми шардами.
Эти паттерны помогают решать основные задачи распределённых систем: масштабирование, отказоустойчивость, распределение данных, асинхронное взаимодействие и согласованность.
Сохрани, чтобы не потерять!
➡️ SQL Ready | #ресурс
⚡️5 фундаментальных курсов по ИБ по цене одного
Это предложение для тех, кто готов войти в новую профессию прямо сейчас!
🔥Пакет курсов за 50 000 ₽ вместо 250 000 ₽:
▪️ Linux CyberPunk - обычная цена 49 500 ₽ (+ Курс идет с официальным дипломом системного администратора!)
▪️ SQL для хакера - обычная цена 15 000 ₽
▪️ HackerPoint - обычная цена ~70 000 ₽
▪️ HackerPoint (Blue vs Red Team) - обычная цена 43 500 ₽
▪️ AI-помощники на Python - обычная цена 71 500 ₽
Вы экономите 200 000 ₽ и получаете полную базу: от работы с терминалом и базами данных до разработки ИИ-агентов и взлома систем.
🔒 Квота: набор на программу ограничен по количеству мест.
🦔Отправь промокод SQLready в чат с менеджером, чтобы закрепить за собой скидку и узнать подробности:
👉@cyacademy_support
COUNT(*) в PostgreSQL: MVCC, visibility map и стоимость выполнения!
В PostgreSQL точный COUNT(*) требует определить количество строк, видимых текущему MVCC snapshot. Глобального счётчика, который можно было бы использовать для транзакционно корректного результата, у таблицы нет:
SELECT COUNT(*)
FROM orders;
Seq Scan, поскольку для точного результата всё равно требуется обработать множество видимых строк:Aggregate
-> Seq Scan on orders
PRIMARY KEY или другого подходящего индекса не гарантирует его использование. Если модель стоимости считает путь через индекс дешевле, PostgreSQL может выполнить запрос через Index Only Scan:Aggregate
-> Index Only Scan using orders_pkey on orders
Index Only Scan не означает получение готового количества записей из индекса. Информация, необходимая для определения MVCC-видимости строк, находится в heap, а не в самом индексе.all-visible, PostgreSQL может считать находящиеся на ней строки видимыми без дополнительного обращения к heap:EXPLAIN (ANALYZE, BUFFERS)
SELECT COUNT(*)
FROM orders;
all-visible сбрасывается и впоследствии может быть снова установлен VACUUM.Index Only Scan может требовать дополнительных обращений к heap:Index Only Scan using orders_pkey on orders
Heap Fetches: 18427
COUNT(*) зависит не только от размера таблицы и наличия индекса, но и от состояния visibility map, характера нагрузки, работы autovacuum, выбранного плана выполнения и состояния кэша PostgreSQL.pg_class:SELECT reltuples::bigint
FROM pg_class
WHERE oid = 'orders'::regclass;
reltuples обновляется, в частности, при VACUUM и ANALYZE и остаётся приблизительной оценкой. Если статистика для таблицы ещё не собиралась, значение может быть -1.
Настройте оценку пользовательских функций!
Для пользовательской функции PostgreSQL позволяет явно указать стоимость вызова через COST, а для функции, возвращающей набор строк, — ожидаемое число строк через ROWS.
Причём пересоздавать функцию не обязательно:
ALTER FUNCTION find_orders(bigint)
ROWS 5;
ALTER FUNCTION expensive_check(jsonb)
COST 500;
COST, тем дороже планировщик считает вычисление и тем сильнее старается не выполнять его лишний раз. COST и ROWS как информацию для оптимизации пользовательских функций. EXPLAIN (ANALYZE, BUFFERS)
SELECT u.id, o.*
FROM users u
CROSS JOIN LATERAL find_orders(u.id) o;
COST и ROWS — иногда правильный план получается без переписывания запроса и новых индексов.
🐱 PostgreSQL Course RU — курс по PostgreSQL и SQL для разработчиков!
В репозитории собраны материалы для изучения работы с базами данных: от основ SQL и проектирования таблиц до функций, индексов, транзакций, оконных функций, PL/pgSQL и продвинутых возможностей PostgreSQL. Отличный вариант, чтобы разобраться с базами данных и перейти от простых запросов к пониманию работы СУБД.
Оставляю ссылочку: GitHub 📱
😎 Очень интересная статья на Хабре: «Как устроено шардирование PG в процессинге Яндекс Такси»!
В этой статье:• Узнаете, зачем крупным системам переходить от одной базы к распределённому хранению данных;• Разберётесь, как работает выбор шарда и какие архитектурные решения помогают масштабировать PostgreSQL;• Посмотрите на инженерные подходы из высоконагруженного продакшена.
🔊 Продолжай читать на Habr!
Двойной NOT EXISTS: реляционное деление без подсчёта строк!
Задачи вида «найти сущности, удовлетворяющие всем условиям из некоторого набора» встречаются регулярно: все разрешения роли, все обязательные атрибуты товара, все зависимости конфигурации или все компетенции проекта. В реляционной алгебре такой класс задач связан с операцией деления.
Предположим, требования проекта и навыки сотрудников представлены отношениями:
project_requirements(project_id, skill_id)
employee_skills(employee_id, skill_id)
42. Один из распространённых вариантов — подсчитать совпадения:SELECT e.id
FROM employees e
JOIN employee_skills s
ON s.employee_id = e.id
JOIN project_requirements r
ON r.project_id = 42
AND r.skill_id = s.skill_id
GROUP BY e.id
HAVING COUNT(DISTINCT r.skill_id) = (
SELECT COUNT(DISTINCT skill_id)
FROM project_requirements
WHERE project_id = 42
);
skill_id не допускает NULL. DISTINCT необходим, если уникальность пар (project_id, skill_id) и (employee_id, skill_id) не гарантирована схемой.SELECT e.id
FROM employees e
WHERE NOT EXISTS (
SELECT 1
FROM project_requirements r
WHERE r.project_id = 42
AND NOT EXISTS (
SELECT 1
FROM employee_skills s
WHERE s.employee_id = e.id
AND s.skill_id = r.skill_id
)
);
NOT EXISTS ищет отсутствие невыполненных требований, а внутренний проверяет отсутствие соответствующего навыка. Важное свойство — дубли не влияют на результат:INSERT INTO employee_skills (employee_id, skill_id)
VALUES
(7, 10),
(7, 10),
(7, 20);
10 и 20, сотрудник 7 удовлетворяет требованиям независимо от числа повторений (7, 10). EXISTS проверяет наличие строки, а не их количество.ALTER TABLE project_requirements
ADD CONSTRAINT uq_project_requirement
UNIQUE (project_id, skill_id);
ALTER TABLE employee_skills
ADD CONSTRAINT uq_employee_skill
UNIQUE (employee_id, skill_id);
skill_id в такой модели обычно следует объявлять NOT NULL. Иначе COUNT(DISTINCT skill_id) игнорирует NULL, а сравнение s.skill_id = r.skill_id с NULL не даст совпадения, что может привести к различию результатов двух подходов.42 вообще нет требований, двойной NOT EXISTS вернёт всех сотрудников: нет ни одного требования, которое сотрудник не выполняет. Если по правилам предметной области проект без требований не должен возвращать кандидатов, это нужно указать отдельно:SELECT e.id
FROM employees e
WHERE EXISTS (
SELECT 1
FROM project_requirements r
WHERE r.project_id = 42
)
AND NOT EXISTS (
SELECT 1
FROM project_requirements r
WHERE r.project_id = 42
AND NOT EXISTS (
SELECT 1
FROM employee_skills s
WHERE s.employee_id = e.id
AND s.skill_id = r.skill_id
)
);
NOT EXISTS полезен тем, что выражает исходную задачу напрямую: вместо подсчёта совпадений мы проверяем отсутствие хотя бы одного невыполненного требования.
PostgreSQL Advisory Locks: синхронизация конкурентных операций!
Блокировок строк недостаточно, когда нужно синхронизировать не конкретную запись, а логическую операцию. Например, два воркера одновременно начинают генерацию одного и того же отчёта для пользователя. Даже если результат в итоге сохраняется с UNIQUE(user_id), это не предотвращает двойное выполнение дорогостоящей работы.
Для таких случаев PostgreSQL предоставляет advisory locks — блокировки, ключ и семантику которых определяет приложение:
SELECT pg_advisory_lock(1001);
pg_advisory_lock() работает на уровне сессии: блокировка сохраняется до явного pg_advisory_unlock() или завершения сессии:SELECT pg_advisory_unlock(1001);
pg_advisory_xact_lock(): такая блокировка автоматически освобождается при COMMIT или ROLLBACK:BEGIN;
SELECT pg_advisory_xact_lock(1, 1001);
-- Здесь выполняется операция, которую нужно сериализовать.
INSERT INTO reports(user_id, created_at)
SELECT 1001, now()
WHERE NOT EXISTS (
SELECT 1
FROM reports
WHERE user_id = 1001
);
COMMIT;
1 можно использовать как namespace операции, а 1001 — как идентификатор ресурса:(1, 1001) — generate_report / user 1001
(2, 1001) — recalculate_stats / user 1001
SELECT pg_try_advisory_xact_lock(1, 1001);
true — lock получен, выполняем работу
false — lock уже удерживается, работу можно пропустить
ALTER TABLE reports
ADD CONSTRAINT reports_user_id_key UNIQUE (user_id);
(1, 1001). Для него это просто ключ блокировки. Поэтому все конкурирующие процессы должны одинаково формировать ключи и захватывать соответствующие locks.
Почему 5 систем могут потребовать 10 интеграций, а 10 — уже 45?
Когда в data stack появляется несколько отдельных инструментов для хранения, обработки и аналитики, между ними приходится выстраивать обмен данными. Для пяти систем таких связок может быть до 10, а для десяти — уже до 45.
Yandex B2B Tech представила DataLens Platform на основе архитектуры lakehouse. Исходные и подготовленные данные хранятся в общей среде на S3 с использованием Apache Iceberg.
Из технических деталей — storage и compute масштабируются независимо. То есть рост объема данных не обязательно означает пропорциональное увеличение вычислительных ресурсов, и наоборот.
👉 Подробнее об архитектуре DataLens Platform — в материале СМИ.
📂 Шпаргалка по SQL для разработчиков!
Например, SELECT используется для получения данных из таблиц, а CREATE, ALTER и DROP помогают управлять структурой базы данных. JOIN позволяет объединять данные из нескольких таблиц, а агрегатные функции (COUNT, SUM, AVG) — анализировать большие объёмы информации.
На картинке — шпаргалка с основными категориями команд, операторами, ключевыми словами, объектами базы данных, ограничениями, функциями агрегации, типами JOIN.
Сохрани, чтобы не потерять!
➡️ SQL Ready | #ресурс
🤔 MentorData — материалы по SQL и аналитике данных!
Авторский блог с материалами для тех, кто изучает SQL, аналитику данных и готовится к работе в этой сфере. Основной акцент сделан не только на синтаксисе, но и на решении аналитических задач и понимании бизнес-логики. В статьях разбираются оконные функции, JOIN, GROUP BY, CTE, работа с аномалиями и метриками, задачи с технических собеседований и подходы к анализу данных.
📌 Оставляю ссылочку: mentordata.ru
➡️ SQL Ready | #ресурс
🖥 Oracle — агрегация данных и отчётность!Шпаргалка по агрегации данных и формированию отчётности в Oracle SQL: объединение значений с LISTAGG, выбор значений по рангу с KEEP (DENSE_RANK FIRST/LAST), построение промежуточных и общих итогов с ROLLUP и GROUPING SETS, а также идентификация уровней агрегации с помощью GROUPING и GROUPING_ID. Полезно для построения сводных выборок, многоуровневых отчётов и обработки агрегированных данных непосредственно средствами SQL.
➡️ SQL Ready | #шпора
Оконный фрейм по группам значений!ROWS считает физические строки. GROUPS считает группы строк с одинаковым значением ORDER BY.
SELECT price,
count(*) OVER (
ORDER BY price
GROUPS BETWEEN 1 PRECEDING AND 1 FOLLOWING
)
FROM products;
dense_rank() и не добавляя ещё один уровень запроса.EXCLUDE, который можно использовать прямо внутри оконного фрейма:SELECT id,
avg(score) OVER (
ORDER BY created_at
ROWS BETWEEN 10 PRECEDING AND 10 FOLLOWING
EXCLUDE CURRENT ROW
) AS neighbors_avg
FROM measurements;
SELECT price,
sum(amount) OVER (
ORDER BY price
GROUPS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
EXCLUDE GROUP
)
FROM sales;
EXCLUDE GROUP исключит из расчёта всю текущую peer-группу, а не только одну строку.GROUPS + EXCLUDE позволяют описывать сложные окна непосредственно в OVER, где обычно появляются dense_rank(), дополнительные CTE и self join.
📂 Шпаргалка по структурам данных!
Например, стек работает по принципу LIFO — последний добавленный элемент извлекается первым, а очередь наоборот использует FIFO — первым выходит тот, кто пришёл первым.
На картинке — 7 основных структур данных: массивы, связные списки, стек, очередь, хеш-таблица, дерево и граф. Полезная база, которую стоит знать каждому разработчику.
Сохрани, чтобы не потерять!
➡️ SQL Ready | #ресурс