DDL: CREATE TABLE, схемы, ALTER

Рейтинг: 68.5% · 14 голосов
Подробный курс по PostgreSQL: SQL по демобазе, типы данных и JSONB, индексы, транзакции и MVCC, VACUUM, EXPLAIN и планировщик, роли и привилегии, репликация, бэкап, настройка под нагрузку и под 1С. Актуально на 2026.
Ответить
Аватара пользователя
Egor_DBA
Сообщения: 47
Зарегистрирован: 11 май 2026, 05:31

DDL: CREATE TABLE, схемы, ALTER

Сообщение Egor_DBA »

Оглавление курса (47)
  1. Что такое PostgreSQL: история, философия, где применяется
  2. Урок 1. Что нового в PostgreSQL 15 и далее (15 -> 16 -> 17)
  3. Установка и первый запуск: Linux, Windows, Docker
  4. psql детально: метакоманды и работа в консоли
  5. Демобаза Авиаперевозки Postgres Pro: структура и развёртывание
  6. SELECT: проекция, фильтрация, сортировка
  7. Транзакции и ACID
  8. Уровни изоляции транзакций: Read Committed, Repeatable Read, Serializable
  9. Соединения таблиц (JOIN)
  10. Агрегация: GROUP BY, HAVING, GROUPING SETS
  11. Подзапросы и CTE (WITH), рекурсия
  12. Оконные функции
  13. Изменение данных: INSERT/UPDATE/DELETE, UPSERT, MERGE
  14. Числовые и булевы типы, NULL и трёхзначная логика
  15. Строки, текст, дата и время, таймзоны
  16. Массивы, диапазоны, enum, составные типы
  17. JSON и JSONB: операторы и индексация
  18. DDL: CREATE TABLE, схемы, ALTER (вы здесь)
  19. Ограничения целостности
  20. Представления и материализованные представления
  21. Последовательности, IDENTITY, генерируемые столбцы
  22. Индексы: B-tree и когда индекс не используется
  23. Типы индексов: Hash, GiST, SP-GiST, GIN, BRIN
  24. Продвинутые индексы: частичные, по выражению, покрывающие
  25. Обслуживание индексов и таблиц: bloat, REINDEX, CONCURRENTLY
  26. Полнотекстовый поиск
  27. Роли и пользователи
  28. Привилегии: GRANT/REVOKE
  29. Row-Level Security и безопасность данных
  30. Подключение приложения: pg_hba.conf, SSL, пулы соединений
  31. Серверное программирование: функции и процедуры
  32. Триггеры и события
  33. Архитектура PostgreSQL: процессы и память
  34. MVCC: версии строк и видимость
  35. VACUUM, autovacuum, freeze и wraparound
  36. WAL, контрольные точки и долговечность
  37. Блокировки и взаимоблокировки
  38. Планировщик запросов
  39. EXPLAIN и EXPLAIN ANALYZE: чтение планов
  40. Конфигурация сервера: ключевые параметры
  41. Настройка под нагрузку и под 1С
  42. Параллельные запросы и партиционирование
  43. Резервное копирование и восстановление
  44. Репликация: потоковая и hot standby
  45. Логическая репликация и кластерные решения
  46. Внешние данные, расширения и сертификация
  47. Разбор планов запросов на explain.tensor.ru: глубокое чтение EXPLAIN ANALYZE
Урок 17. DDL: CREATE TABLE, схемы, ALTER

DDL (Data Definition Language) - это команды, которые описывают структуру базы: создают таблицы, меняют столбцы, раскладывают объекты по схемам. В этом уроке разберём, как в postgresql завести таблицу с правильными типами данных и значениями по умолчанию, как потом безопасно её переделать через ALTER TABLE (и почему один ALTER может положить нагрузку, а другой - нет), как организовать объекты по схемам и search_path, что такое tablespaces и зачем нужны временные и нелогируемые таблицы. Цель проста: чтобы ваша схема не превратилась через год в свалку, а изменения на проде не вызывали долгих блокировок.

Изображение

Как это работает

Таблица в PostgreSQL - это не просто сетка строк, а набор столбцов, каждый со своим типом. Тип определяет, что туда влезет и сколько места займёт. Когда вы пишете CREATE TABLE, планировщик и движок начинают полагаться на эти типы при проверках, индексах и оценках. Поэтому выбор типа - это не косметика, а основа корректности.

DEFAULT задаёт значение, которое подставится, если столбец не указан в INSERT. Важная деталь: DEFAULT вычисляется в момент вставки строки, а не в момент создания таблицы. Поэтому now() в DEFAULT даст время каждой вставки, а не время CREATE TABLE.

Схема - это пространство имён внутри одной базы. Объекты с одинаковым именем могут жить в разных схемах и не конфликтовать. Какую схему PostgreSQL подставит, если вы написали просто имя таблицы без префикса, решает параметр search_path - это упорядоченный список схем, который сервер просматривает слева направо. По умолчанию там public, но в нормальном проекте схемы разделяют по доменам или модулям.

ALTER TABLE меняет уже существующую таблицу. Ключевой вопрос здесь - блокировки. Многие формы ALTER берут блокировку ACCESS EXCLUSIVE на таблицу, то есть на это время к ней нельзя ни читать, ни писать. Хорошая новость: добавление столбца с обычным DEFAULT с версии 11 происходит мгновенно, без переписывания всех строк (метаданные хранят default отдельно). А вот смена типа столбца обычно требует полной перезаписи таблицы и долгой блокировки.

Tablespace - это привязка объекта к каталогу на диске. Через tablespaces можно разнести тяжёлые таблицы на отдельный (например, быстрый) накопитель, не трогая логику. Временные (TEMP) таблицы видны только внутри сессии и исчезают по её завершении. Нелогируемые (UNLOGGED) таблицы не пишутся в WAL: вставки в них быстрее, но при сбое сервера их содержимое обнуляется и они не реплицируются. Это инструмент для промежуточных данных, не для боевых.

SQL и примеры

Создадим рабочую схему и простую таблицу заметок об аэропортах поверх демобазы bookings (демобаза Авиаперевозки от Postgres Professional):

Код: Выделить всё

CREATE SCHEMA ops;

CREATE TABLE ops.airport_notes (
    id          bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    airport     char(3) NOT NULL,
    note        text    NOT NULL,
    is_active   boolean NOT NULL DEFAULT true,
    created_at  timestamptz NOT NULL DEFAULT now()
);
Здесь id - суррогатный ключ через GENERATED ALWAYS AS IDENTITY (современная замена serial, стандарт SQL). created_at получает now() в момент вставки. Тип char(3) под код аэропорта, как airport_code в bookings.airports.

Свяжем заметки с реальными аэропортами и посмотрим активные:

Код: Выделить всё

INSERT INTO ops.airport_notes (airport, note)
SELECT airport_code, 'нужна проверка стоек'
FROM bookings.airports
WHERE airport_code IN ('SVO', 'LED', 'KJA');

SELECT n.airport, a.airport_name, n.created_at
FROM ops.airport_notes n
JOIN bookings.airports a ON a.airport_code = n.airport
WHERE n.is_active;
Первый запрос вставляет три заметки, второй джойнит их с таблицей аэропортов демобазы и показывает только активные.

Теперь ALTER TABLE. Добавим столбец с дефолтом (быстро, без перезаписи) и аккуратно поменяем тип:

Код: Выделить всё

ALTER TABLE ops.airport_notes
    ADD COLUMN priority integer NOT NULL DEFAULT 0;

ALTER TABLE ops.airport_notes
    ALTER COLUMN note TYPE varchar(500) USING left(note, 500);
Первый ALTER добавит priority мгновенно. Второй меняет тип note и потому перепишет таблицу под блокировкой - на большой таблице это надо делать в окно.

Управление search_path, чтобы не писать ops. перед каждым именем:

Код: Выделить всё

SHOW search_path;
SET search_path TO ops, bookings, public;
SELECT count(*) FROM airport_notes;
Временная и нелогируемая таблицы для разовых вычислений:

Код: Выделить всё

CREATE TEMP TABLE tmp_top_airports AS
SELECT departure_airport, count(*) AS cnt
FROM bookings.flights
GROUP BY departure_airport;

CREATE UNLOGGED TABLE ops.import_staging (
    raw_line text
);
TEMP-таблица живёт до конца сессии, UNLOGGED-таблица переживает сессию, но не сбой и не репликацию - идеально под стейджинг импорта.

Частые грабли
  • Думают, что DEFAULT now() запоминает момент создания таблицы. Нет, оно вычисляется при каждой вставке.
  • Меняют тип столбца на большой таблице в рабочее время и ловят долгую блокировку ACCESS EXCLUSIVE - все запросы к таблице висят.
  • Кладут всё в public и потом не могут разделить права. Схемы - это и про порядок, и про доступ.
  • Забывают, что UNLOGGED-таблица обнуляется при крахе сервера и не попадает на реплику. Для важных данных это потеря.
  • Ставят search_path так, что одноимённый объект из чужой схемы перехватывает запрос. Порядок схем в списке важен.
  • Используют serial в новых проектах. Лучше GENERATED ... AS IDENTITY: чище права и поведение, это рекомендуемый способ в актуальных версиях.
  • Льют char(N) на тексты переменной длины. Для большинства задач берите text или varchar, char дополняет пробелами.
Мини-лаба
  • Создайте схему lab: CREATE SCHEMA lab;
  • Создайте таблицу lab.flight_audit с id (GENERATED ALWAYS AS IDENTITY), flight_id integer, status text DEFAULT 'new', changed_at timestamptz DEFAULT now().
  • Вставьте 3 строки, указав только flight_id, и проверьте, что status и changed_at заполнились сами.
  • Через ALTER TABLE добавьте столбец comment text DEFAULT '' и убедитесь по \d lab.flight_audit, что он появился.
  • Сделайте SET search_path TO lab; и выполните запрос к flight_audit без префикса схемы.
  • Создайте CREATE UNLOGGED TABLE lab.scratch (x int), вставьте данные, сравните скорость с обычной таблицей на большом INSERT.
  • Удалите учебные объекты: DROP SCHEMA lab CASCADE;
Контрольные вопросы
  • В какой момент вычисляется выражение в DEFAULT и почему это важно для now()?
  • Почему ADD COLUMN с DEFAULT теперь быстрый, а ALTER COLUMN TYPE - нет?
  • Как search_path влияет на то, к какой именно таблице обратится запрос без указания схемы?
  • Чем UNLOGGED-таблица отличается от обычной и от TEMP по времени жизни и надёжности?
  • Зачем нужны tablespaces и какую задачу они решают на уровне физического хранения?
  • Почему GENERATED AS IDENTITY предпочитают serial в новых схемах?
👍3 ❤️1 🔥2 😄 🤔
Аватара пользователя
elastic7
Сообщения: 1
Зарегистрирован: 13 май 2026, 00:22

Re: DDL: CREATE TABLE, схемы, ALTER

Сообщение elastic7 »

А если у меня одинаковые имена таблиц в двух схемах и я забыл префикс - оно молча возьмёт первую по search_path или ошибку кинет? боюсь напороться на проде
👍 ❤️1 🔥1 😄 🤔
Аватара пользователя
sanya95
Сообщения: 1
Зарегистрирован: 20 май 2026, 15:24

Re: DDL: CREATE TABLE, схемы, ALTER

Сообщение sanya95 »

проверил ADD COLUMN с DEFAULT на таблице в 40 млн строк - реально мгновенно, спасибо. а вот ALTER TYPE с int на bigint встал колом, делал ночью
👍 ❤️ 🔥1 😄 🤔
Ответить
← Предыдущая глава
JSON и JSONB: операторы и индексация
Следующая глава →
Ограничения целостности

Все главы курса «PostgreSQL: от первого запроса до продакшена»

Поделиться темой: ✈ Telegram VK

Вернуться в «PostgreSQL: от первого запроса до продакшена»

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 2 гостя