Развернутые методические указания к проведению теоретического занятия по синтаксису, механизмам выполнения, транзакционному протоколированию и оптимизации DML-операторов (INSERT, UPDATE, DELETE, TRUNCATE) в СУБД PostgreSQL.
Настоящее занятие открывает фундаментальный блок языка манипулирования данными (Data Manipulation Language — DML). Если предыдущие занятия были сфокусированы на проектировании статических схем и декларативных ограничениях целостности (DDL), то данное занятие переводит студентов в плоскость динамической обработки информации в промышленных реляционных СУБД.
INSERT, UPDATE, DELETE; изучить расширенные механизмы манипулирования данными: пакетную вставку (multi-row), подзапросы в DML, возврат генерируемых колонок через RETURNING, идемпотентное слияние (UPSERT через ON CONFLICT DO UPDATE / DO NOTHING); раскрыть фундаментальные различия между DELETE и TRUNCATE на уровне журнала предзаписи WAL, блокировок таблиц и MVCC.В зависимости от графика учебного процесса преподаватель применяет основной 80-минутный регламент пары (двойной академический час) либо сокращенный 60-минутный регламент. Структура этапов сохраняется, оптимизируется глубина разбора кейсов и длительность дискуссионной части.
| Этап занятия | Основной (80 мин) | Сокращенный (60 мин) | Ключевая деятельность преподавателя и студентов |
|---|---|---|---|
| 1. Организационный момент и мотивация | 5 минут | 3 минуты | Приветствие, фиксация явки. Мотивационный кейс: аварийное выполнение UPDATE без WHERE на 1.5 млн записей биллинга и сбой продакшна. Формулировка целей. |
| 2. Актуализация опорных знаний | 8 минут | 5 минут | Блиц-опрос: ограничения PRIMARY KEY, UNIQUE, FOREIGN KEY, поведение автоинкрементных полей (SERIAL, IDENTITY) и назначение транзакций. |
| 3. Сообщение новых знаний: Лекция | 37 минут | 27 минут | Интерактивная лекция с презентацией: синтаксис INSERT (одиночный, batch, INSERT...SELECT), псевдотаблица EXCLUDED и UPSERT, UPDATE с FROM/JOIN, подзапросы, RETURNING, DELETE vs TRUNCATE, влияние на WAL и B-Tree индексы. |
| 4. Разбор эталонного инженерного кейса | 12 минут | 10 минут | Демонстрация сквозного кейса на проекторе в psql: пакетная вставка накладной склада, разрешение коллизии остатка товара через UPSERT, отбор удаляемых записей с фиксацией в аудите через RETURNING. |
| 5. Первичное закрепление материала | 12 минут | 11 минут | Индивидуальная экспресс-работа с интерактивным рабочим листом zanyatie.html по 4 вариантам, проектирование комплексных DML-запросов, самопроверка. |
| 6. Подведение итогов, рефлексия, ДЗ | 6 минут | 4 минуты | Разбор слайда 15 с культовым интернет-мемом Bobby Tables (xkcd #327), анализ типичных ошибок, инструктаж по резервному ДЗ domashnee_zadanie.html. |
Оператор INSERT INTO предназначен для добавления новых строк в таблицу. В современных высоконагруженных системах одиночные вставки уступают место пакетированным и декларативно-безопасным операциям.
-- Одиночная вставка с явным указанием целевых атрибутов
INSERT INTO warehouse_inventory (sku, product_name, quantity, unit_price)
VALUES ('SKU-00124', 'SSD NVMe 1TB Samsung 980', 45, 8490.00);
VALUES. В отличие от N отдельных запросов, многострочный INSERT генерирует одну транзакцию, один сетевой раунд-трип к серверу и существенно снижает накладные расходы на парсинг SQL и запись в журнал предзаписи WAL.-- Пакетная вставка (Batch / Multi-row INSERT) 5 позиций
INSERT INTO warehouse_inventory (sku, product_name, quantity, unit_price)
VALUES
('SKU-101', 'Процессор Intel Core i5-13400', 15, 18200.00),
('SKU-102', 'Материнская плата B760 DDR5', 20, 12500.00),
('SKU-103', 'Модуль памяти DDR5 32GB Kit', 35, 9800.00),
('SKU-104', 'Блок питания 750W Gold', 18, 8100.00),
('SKU-105', 'Корпус ATX Mesh Black', 12, 5400.00)
RETURNING id, sku, created_at;
-- Перенос закрытых договоров в архивную таблицу
INSERT INTO contracts_archive (contract_id, client_id, close_date, final_balance)
SELECT c.id, c.client_id, c.closed_at, c.balance
FROM active_contracts c
WHERE c.status = 'CLOSED' AND c.closed_at < CURRENT_DATE - INTERVAL '1 year';
SELECT. Критически важно для получения значений суррогатных первичных ключей (id), значений по умолчанию (DEFAULT) или вычисляемых триггерами колонок.До стандарта SQL:2016 для реализации паттерна «вставить, если нет, или обновить, если уже существует» разработчики прибегали к сложным процедурам с проверками IF EXISTS, страдающим от состояния гонки (Race Condition). В PostgreSQL реализован механизм атомарного разрешения конфликтов через конструкцию ON CONFLICT (target_column):
DO NOTHING — операция игнорирует строки, вызывающие нарушение уникальности первичного или альтернативного ключа. Строка не вставляется, ошибка unique_violation подавляется.DO UPDATE SET ... — при коллизии уникальности СУБД выполняет модификацию существующей строки. Доступ к значениям, которые предполагалось вставить, осуществляется через специальную виртуальную псевдотаблицу EXCLUDED.-- Идемпотентный UPSERT складских остатков при повторной поставке
INSERT INTO warehouse_inventory (sku, product_name, quantity, unit_price)
VALUES ('SKU-101', 'Процессор Intel Core i5-13400', 10, 17900.00)
ON CONFLICT (sku)
DO UPDATE SET
quantity = warehouse_inventory.quantity + EXCLUDED.quantity,
unit_price = EXCLUDED.unit_price,
updated_at = CURRENT_TIMESTAMP
RETURNING warehouse_inventory.id, warehouse_inventory.sku, warehouse_inventory.quantity;
Оператор UPDATE изменяет существующие кортежи. В реляционной архитектуре СУБД с моделью многоверсионности (MVCC) операция UPDATE физически представляет собой связку «пометить старую версию мертвой (dead tuple) + вставить новую версию (new tuple)».
WHERE. Пропуск предиката приводит к немедленной перезаписи всей таблицы.FROM, чтобы избежать декартова произведения!-- Обновление статуса медицинского приема по состоянию счета в таблице Оплаты
UPDATE doctor_appointments AS a
SET
status = 'CONFIRMED',
updated_at = CURRENT_TIMESTAMP
FROM payment_invoices AS p
WHERE a.id = p.appointment_id
AND p.payment_status = 'PAID'
AND a.status = 'PENDING_PAYMENT'
RETURNING a.id, a.patient_id, a.doctor_id, a.status;
-- Массовое начисление процентов по кредитам на основе статуса профиля заемщика
UPDATE credit_contracts AS c
SET accrued_interest = accrued_interest + (c.principal_debt * c.interest_rate / 365)
WHERE c.status = 'ACTIVE'
AND EXISTS (
SELECT 1 FROM client_profiles p
WHERE p.id = c.client_id AND p.is_blocked = FALSE
)
RETURNING c.id, c.client_id, c.accrued_interest;
Оператор DELETE удаляет строки, удовлетворяющие условию предиката WHERE. В PostgreSQL удаленные строки не освобождают место на диске немедленно: кортеж помечается удаленным в заголовке строки (устанавливается метка xmax, равная идентификатору текущей транзакции). Пространство очищается фоновым процессом VACUUM.
-- Селективное удаление отмененных приемов старше 1 года с возвратом данных
DELETE FROM doctor_appointments
WHERE status = 'CANCELLED'
AND appointment_date < CURRENT_DATE - INTERVAL '1 year'
RETURNING id, patient_fio, appointment_date, cancellation_reason;
Сравнение операторов DELETE и TRUNCATE — классический вопрос инженерных собеседований и важный раздел дисциплины. Студенты часто ошибочно считают TRUNCATE синтаксическим сахаром для «DELETE без WHERE».
| Характеристика | Оператор DELETE | Оператор TRUNCATE |
|---|---|---|
| Категория языка | DML (Data Manipulation Language) | DDL (Data Definition Language) |
| Уровень блокировки | ROW EXCLUSIVE (позволяет параллельные SELECT и чтение других строк) |
ACCESS EXCLUSIVE (полная монопольная блокировка таблицы, блокирует любые SELECT) |
| Журналирование WAL (Write-Ahead Log) | Записывает в журнал каждую удаляемую строку (высокая нагрузка на дисковый ввод/вывод при миллионах строк) | Записывает только факт отсечения страниц и выделения нового файлового узла (минимальный объем WAL) |
| Физическое освобождение диска | Дисковое пространство НЕ возвращается ОС; образуются «мертвые кортежи» (bloat), требующие VACUUM |
Мгновенно освобождает дисковые страницы путем пересоздания файла таблицы (новый relfilenode) |
| Индексные структуры | Обходит B-Tree индексы, помечая ссылки; размер индексных файлов не уменьшается до REINDEX/VACUUM | Мгновенно пересоздает B-Tree индексы как абсолютно пустые структуры |
| Счетчики автоинкремента | Не сбрасывает значение IDENTITY / SEQUENCE (следующая вставка продолжит счетчик) |
Поддерживает опцию RESTART IDENTITY (по умолчанию CONTINUE IDENTITY) |
| Поддержка условий (WHERE) | Да, удаляет любые селективные подмножества данных | Нет, очищает таблицу целиком (или указанные партиции) |
| Срабатывание триггеров | Вызывает триггеры уровня строки (FOR EACH ROW) и уровня оператора |
Вызывает ТОЛЬКО триггеры TRUNCATE уровня оператора (FOR EACH STATEMENT) |
UPDATE users SET is_active = false; на рабочей базе в 10 миллионов клиентов, парализовав авторизацию. Этот прием моментально приковывает внимание и прививает привычку оборачивать любые ручные модификации в транзакции: BEGIN; ... ROLLBACK;.DELETE FROM test_data; (занимает 14.8 секунд, генерирует 120 Мб WAL) и через TRUNCATE test_data; (выполняется за 4 миллисекунды). Разница в 3500 раз производит неизгладимое впечатление на студентов.| Типовая ошибка | Симптомы и поведение СУБД | Педагогическое исправление |
|---|---|---|
| UPDATE / DELETE без секции WHERE | СУБД модифицирует или очищает абсолютно все строки таблицы. | Приучать студентов перед запуском UPDATE/DELETE писать проверочный SELECT COUNT(*) FROM table WHERE condition; и использовать явные транзакции BEGIN...ROLLBACK. |
| Синтаксическая ошибка в JOIN при UPDATE | Попытка написать UPDATE a JOIN b ON ... (синтаксис MySQL/MS SQL), что вызывает синтаксическую ошибку в PostgreSQL. |
Разъяснить стандартную для PostgreSQL конструкцию UPDATE a SET ... FROM b WHERE a.id = b.a_id. |
| Путаница между именами колонок в UPSERT | Написание SET col = col + quantity вместо SET col = table.col + EXCLUDED.quantity. |
Показать, что без префикса EXCLUDED СУБД либо сошлется на старое значение, либо выдаст ошибку неоднозначности (ambiguous column). |
| Несоответствие столбцов в INSERT...SELECT | Ошибка несовместимости типов datatype mismatch либо запись данных не в те поля из-за несовпадения порядка. |
Требовать строгого явного указания списка колонок в круглых скобках как у целевой таблицы, так и в SELECT-проекции. |
Контроль сформированности знаний и умений осуществляется по прозрачной 4-балльной шкале в соответствии с паспортом занятия:
WHERE, исключающие случайную порчу соседних строк данных.RETURNING для возврата ключевых атрибутов и реализует операцию ON CONFLICT ... DO UPDATE/DO NOTHING с корректным обращением к псевдотаблице EXCLUDED.DELETE и TRUNCATE, понимает транзакционные последствия (WAL, блокировки) и успешно отвечает на контрольные вопросы.Итоговая дифференциация: 4 балла — отлично (материал освоен в полном объеме); 3 балла — хорошо (допущены незначительные синтаксические погрешности); 2 балла — удовлетворительно (выполнены только базовые команды); 1-0 баллов — не зачтено.